diff --git a/.travis.yml b/.travis.yml index 925e23b1a5..4f5d482c65 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ jobs: - stage: lint os: linux dist: bionic - go: 1.20.x + go: 1.21.x env: - lint git: @@ -28,7 +28,7 @@ jobs: os: linux arch: amd64 dist: bionic - go: 1.20.x + go: 1.21.x env: - docker services: @@ -45,7 +45,7 @@ jobs: os: linux arch: arm64 dist: bionic - go: 1.20.x + go: 1.21.x env: - docker services: @@ -63,10 +63,9 @@ jobs: os: linux dist: bionic sudo: required - go: 1.20.x + go: 1.21.x env: - azure-linux - - GO111MODULE=on git: submodules: false # avoid cloning ethereum/tests addons: @@ -97,10 +96,9 @@ jobs: - stage: build if: type = push os: osx - go: 1.20.x + go: 1.21.x env: - azure-osx - - GO111MODULE=on git: submodules: false # avoid cloning ethereum/tests script: @@ -112,41 +110,34 @@ jobs: os: linux arch: amd64 dist: bionic - go: 1.20.x - env: - - GO111MODULE=on + go: 1.21.x script: - - go run build/ci.go test $TEST_PACKAGES + - travis_wait 30 go run build/ci.go test $TEST_PACKAGES - stage: build if: type = pull_request os: linux arch: arm64 dist: bionic - go: 1.19.x - env: - - GO111MODULE=on + go: 1.20.x script: - - go run build/ci.go test $TEST_PACKAGES + - travis_wait 30 go run build/ci.go test $TEST_PACKAGES - stage: build os: linux dist: bionic - go: 1.19.x - env: - - GO111MODULE=on + go: 1.20.x script: - - go run build/ci.go test $TEST_PACKAGES + - travis_wait 30 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]/) os: linux dist: bionic - go: 1.20.x + go: 1.21.x env: - ubuntu-ppa - - GO111MODULE=on git: submodules: false # avoid cloning ethereum/tests addons: @@ -167,10 +158,9 @@ jobs: if: type = cron os: linux dist: bionic - go: 1.20.x + go: 1.21.x env: - azure-purge - - GO111MODULE=on git: submodules: false # avoid cloning ethereum/tests script: @@ -181,9 +171,7 @@ jobs: if: type = cron os: linux dist: bionic - go: 1.20.x - env: - - GO111MODULE=on + go: 1.21.x script: - - go run build/ci.go test -race $TEST_PACKAGES + - travis_wait 30 go run build/ci.go test -race $TEST_PACKAGES diff --git a/Dockerfile b/Dockerfile index 1951fed8ef..ed69a04789 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ ARG VERSION="" ARG BUILDNUM="" # Build Geth in a stock Go builder container -FROM golang:1.20-alpine as builder +FROM golang:1.21-alpine as builder RUN apk add --no-cache gcc musl-dev linux-headers git diff --git a/Makefile b/Makefile index e6286da7fb..d736ef61c0 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ GOBIN = ./build/bin GO ?= latest -GORUN = env GO111MODULE=on go run +GORUN = go run geth: $(GORUN) build/ci.go install ./cmd/geth @@ -23,7 +23,7 @@ lint: ## Run linters. $(GORUN) build/ci.go lint clean: - env GO111MODULE=on go clean -cache + go clean -cache rm -fr build/_workspace/pkg/ $(GOBIN)/* # The devtools target installs tools required for 'go generate'. diff --git a/README.md b/README.md index 34bd8b94c9..77317090c1 100644 --- a/README.md +++ b/README.md @@ -123,15 +123,6 @@ use separate accounts for play and real money. Unless you manually move accounts, `geth` will by default correctly separate the two networks and will not make any accounts available between them.* -### Full node on the Rinkeby test network - -Go Ethereum also supports connecting to the older proof-of-authority based test network -called [*Rinkeby*](https://www.rinkeby.io) which is operated by members of the community. - -```shell -$ geth --rinkeby console -``` - ### Configuration As an alternative to passing the numerous flags to the `geth` binary, you can also pass a diff --git a/accounts/abi/abi.go b/accounts/abi/abi.go index 62b860e18c..6e1075c715 100644 --- a/accounts/abi/abi.go +++ b/accounts/abi/abi.go @@ -22,6 +22,7 @@ import ( "errors" "fmt" "io" + "math/big" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" @@ -222,6 +223,17 @@ func (abi *ABI) EventByID(topic common.Hash) (*Event, error) { return nil, fmt.Errorf("no event with id: %#x", topic.Hex()) } +// ErrorByID looks up an error by the 4-byte id, +// returns nil if none found. +func (abi *ABI) ErrorByID(sigdata [4]byte) (*Error, error) { + for _, errABI := range abi.Errors { + if bytes.Equal(errABI.ID[:4], sigdata[:]) { + return &errABI, nil + } + } + return nil, fmt.Errorf("no error with id: %#x", sigdata[:]) +} + // HasFallback returns an indicator whether a fallback function is included. func (abi *ABI) HasFallback() bool { return abi.Fallback.Type == Fallback @@ -235,24 +247,65 @@ func (abi *ABI) HasReceive() bool { // revertSelector is a special function selector for revert reason unpacking. var revertSelector = crypto.Keccak256([]byte("Error(string)"))[:4] +// panicSelector is a special function selector for panic reason unpacking. +var panicSelector = crypto.Keccak256([]byte("Panic(uint256)"))[:4] + +// panicReasons map is for readable panic codes +// see this linkage for the deails +// https://docs.soliditylang.org/en/v0.8.21/control-structures.html#panic-via-assert-and-error-via-require +// the reason string list is copied from ether.js +// https://github.com/ethers-io/ethers.js/blob/fa3a883ff7c88611ce766f58bdd4b8ac90814470/src.ts/abi/interface.ts#L207-L218 +var panicReasons = map[uint64]string{ + 0x00: "generic panic", + 0x01: "assert(false)", + 0x11: "arithmetic underflow or overflow", + 0x12: "division or modulo by zero", + 0x21: "enum overflow", + 0x22: "invalid encoded storage byte array accessed", + 0x31: "out-of-bounds array access; popping on an empty array", + 0x32: "out-of-bounds access of an array or bytesN", + 0x41: "out of memory", + 0x51: "uninitialized function", +} + // UnpackRevert resolves the abi-encoded revert reason. According to the solidity // spec https://solidity.readthedocs.io/en/latest/control-structures.html#revert, -// the provided revert reason is abi-encoded as if it were a call to a function -// `Error(string)`. So it's a special tool for it. +// the provided revert reason is abi-encoded as if it were a call to function +// `Error(string)` or `Panic(uint256)`. So it's a special tool for it. func UnpackRevert(data []byte) (string, error) { if len(data) < 4 { return "", errors.New("invalid data for unpacking") } - if !bytes.Equal(data[:4], revertSelector) { + switch { + case bytes.Equal(data[:4], revertSelector): + typ, err := NewType("string", "", nil) + if err != nil { + return "", err + } + unpacked, err := (Arguments{{Type: typ}}).Unpack(data[4:]) + if err != nil { + return "", err + } + return unpacked[0].(string), nil + case bytes.Equal(data[:4], panicSelector): + typ, err := NewType("uint256", "", nil) + if err != nil { + return "", err + } + unpacked, err := (Arguments{{Type: typ}}).Unpack(data[4:]) + if err != nil { + return "", err + } + pCode := unpacked[0].(*big.Int) + // uint64 safety check for future + // but the code is not bigger than MAX(uint64) now + if pCode.IsUint64() { + if reason, ok := panicReasons[pCode.Uint64()]; ok { + return reason, nil + } + } + return fmt.Sprintf("unknown panic code: %#x", pCode), nil + default: return "", errors.New("invalid data for unpacking") } - typ, err := NewType("string", "", nil) - if err != nil { - return "", err - } - unpacked, err := (Arguments{{Type: typ}}).Unpack(data[4:]) - if err != nil { - return "", err - } - return unpacked[0].(string), nil } diff --git a/accounts/abi/abi_test.go b/accounts/abi/abi_test.go index 96c11e0964..84175df4bb 100644 --- a/accounts/abi/abi_test.go +++ b/accounts/abi/abi_test.go @@ -1057,6 +1057,34 @@ func TestABI_EventById(t *testing.T) { } } +func TestABI_ErrorByID(t *testing.T) { + abi, err := JSON(strings.NewReader(`[ + {"inputs":[{"internalType":"uint256","name":"x","type":"uint256"}],"name":"MyError1","type":"error"}, + {"inputs":[{"components":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"string","name":"b","type":"string"},{"internalType":"address","name":"c","type":"address"}],"internalType":"struct MyError.MyStruct","name":"x","type":"tuple"},{"internalType":"address","name":"y","type":"address"},{"components":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"string","name":"b","type":"string"},{"internalType":"address","name":"c","type":"address"}],"internalType":"struct MyError.MyStruct","name":"z","type":"tuple"}],"name":"MyError2","type":"error"}, + {"inputs":[{"internalType":"uint256[]","name":"x","type":"uint256[]"}],"name":"MyError3","type":"error"} + ]`)) + if err != nil { + t.Fatal(err) + } + for name, m := range abi.Errors { + a := fmt.Sprintf("%v", &m) + var id [4]byte + copy(id[:], m.ID[:4]) + m2, err := abi.ErrorByID(id) + if err != nil { + t.Fatalf("Failed to look up ABI error: %v", err) + } + b := fmt.Sprintf("%v", m2) + if a != b { + t.Errorf("Error %v (id %x) not 'findable' by id in ABI", name, id) + } + } + // test unsuccessful lookups + if _, err = abi.ErrorByID([4]byte{}); err == nil { + t.Error("Expected error: no error with this id") + } +} + // TestDoubleDuplicateMethodNames checks that if transfer0 already exists, there won't be a name // conflict and that the second transfer method will be renamed transfer1. func TestDoubleDuplicateMethodNames(t *testing.T) { @@ -1145,6 +1173,8 @@ func TestUnpackRevert(t *testing.T) { {"", "", errors.New("invalid data for unpacking")}, {"08c379a1", "", errors.New("invalid data for unpacking")}, {"08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000d72657665727420726561736f6e00000000000000000000000000000000000000", "revert reason", nil}, + {"4e487b710000000000000000000000000000000000000000000000000000000000000000", "generic panic", nil}, + {"4e487b7100000000000000000000000000000000000000000000000000000000000000ff", "unknown panic code: 0xff", nil}, } for index, c := range cases { t.Run(fmt.Sprintf("case %d", index), func(t *testing.T) { diff --git a/accounts/abi/bind/backend.go b/accounts/abi/bind/backend.go index c16990f395..34530a6455 100644 --- a/accounts/abi/bind/backend.go +++ b/accounts/abi/bind/backend.go @@ -29,7 +29,7 @@ import ( var ( // ErrNoCode is returned by call and transact operations for which the requested // recipient contract to operate on does not exist in the state db or does not - // have any code associated with it (i.e. suicided). + // have any code associated with it (i.e. self-destructed). ErrNoCode = errors.New("no contract code at given address") // ErrNoPendingState is raised when attempting to perform a pending state action diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index 0af520b5d9..0c4342c494 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -681,7 +681,7 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa // Get the last block block, err := b.blockByHash(ctx, b.pendingBlock.ParentHash()) if err != nil { - return fmt.Errorf("could not fetch parent") + return errors.New("could not fetch parent") } // Check transaction validity signer := types.MakeSigner(b.blockchain.Config(), block.Number(), block.Time()) @@ -815,7 +815,7 @@ func (b *SimulatedBackend) AdjustTime(adjustment time.Duration) error { // Get the last block block := b.blockchain.GetBlockByHash(b.pendingBlock.ParentHash()) if block == nil { - return fmt.Errorf("could not find parent") + return errors.New("could not find parent") } blocks, _ := core.GenerateChain(b.config, block, ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) { @@ -892,7 +892,7 @@ func (fb *filterBackend) GetReceipts(ctx context.Context, hash common.Hash) (typ } func (fb *filterBackend) GetLogs(ctx context.Context, hash common.Hash, number uint64) ([][]*types.Log, error) { - logs := rawdb.ReadLogs(fb.db, hash, number, fb.bc.Config()) + logs := rawdb.ReadLogs(fb.db, hash, number) return logs, nil } diff --git a/accounts/abi/bind/backends/simulated_test.go b/accounts/abi/bind/backends/simulated_test.go index 698bfc5765..11900a6cf5 100644 --- a/accounts/abi/bind/backends/simulated_test.go +++ b/accounts/abi/bind/backends/simulated_test.go @@ -161,6 +161,7 @@ func TestAdjustTime(t *testing.T) { func TestNewAdjustTimeFail(t *testing.T) { testAddr := crypto.PubkeyToAddress(testKey.PublicKey) sim := simTestBackend(testAddr) + defer sim.blockchain.Stop() // Create tx and send head, _ := sim.HeaderByNumber(context.Background(), nil) // Should be child's, good enough diff --git a/accounts/abi/bind/template.go b/accounts/abi/bind/template.go index c22eb4ae84..95dc13cc18 100644 --- a/accounts/abi/bind/template.go +++ b/accounts/abi/bind/template.go @@ -325,7 +325,7 @@ var ( if err != nil { return *outstruct, err } - {{range $i, $t := .Normalized.Outputs}} + {{range $i, $t := .Normalized.Outputs}} outstruct.{{.Name}} = *abi.ConvertType(out[{{$i}}], new({{bindtype .Type $structs}})).(*{{bindtype .Type $structs}}){{end}} return *outstruct, err @@ -335,7 +335,7 @@ var ( } {{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}} } @@ -378,7 +378,7 @@ var ( } {{end}} - {{if .Fallback}} + {{if .Fallback}} // Fallback is a paid mutator transaction binding the contract fallback function. // // Solidity: {{.Fallback.Original.String}} @@ -392,16 +392,16 @@ var ( 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}} + {{if .Receive}} // Receive is a paid mutator transaction binding the contract receive function. // // Solidity: {{.Receive.Original.String}} @@ -415,9 +415,9 @@ var ( 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) diff --git a/accounts/abi/error.go b/accounts/abi/error.go index f53c996def..218a22f1e4 100644 --- a/accounts/abi/error.go +++ b/accounts/abi/error.go @@ -32,7 +32,7 @@ type Error struct { str string // Sig contains the string signature according to the ABI spec. - // e.g. error foo(uint32 a, int b) = "foo(uint32,int256)" + // e.g. error foo(uint32 a, int b) = "foo(uint32,int256)" // Please note that "int" is substitute for its canonical representation "int256" Sig string @@ -78,7 +78,7 @@ func NewError(name string, inputs Arguments) Error { } } -func (e *Error) String() string { +func (e Error) String() string { return e.str } diff --git a/accounts/abi/method.go b/accounts/abi/method.go index f69e3ee9b5..b6e1eef3cf 100644 --- a/accounts/abi/method.go +++ b/accounts/abi/method.go @@ -127,11 +127,12 @@ func NewMethod(name string, rawName string, funType FunctionType, mutability str state = state + " " } identity := fmt.Sprintf("function %v", rawName) - if funType == Fallback { + switch funType { + case Fallback: identity = "fallback" - } else if funType == Receive { + case Receive: identity = "receive" - } else if funType == Constructor { + case Constructor: identity = "constructor" } str := fmt.Sprintf("%v(%v) %sreturns(%v)", identity, strings.Join(inputNames, ", "), state, strings.Join(outputNames, ", ")) diff --git a/accounts/abi/method_test.go b/accounts/abi/method_test.go index 395a528965..9230e307aa 100644 --- a/accounts/abi/method_test.go +++ b/accounts/abi/method_test.go @@ -84,11 +84,12 @@ func TestMethodString(t *testing.T) { for _, test := range table { var got string - if test.method == "fallback" { + switch test.method { + case "fallback": got = abi.Fallback.String() - } else if test.method == "receive" { + case "receive": got = abi.Receive.String() - } else { + default: got = abi.Methods[test.method].String() } if got != test.expectation { diff --git a/accounts/abi/reflect.go b/accounts/abi/reflect.go index 1f84b111a3..48d2ef41ec 100644 --- a/accounts/abi/reflect.go +++ b/accounts/abi/reflect.go @@ -228,7 +228,7 @@ func mapArgNamesToStructFields(argNames []string, value reflect.Value) (map[stri structFieldName := ToCamelCase(argName) if structFieldName == "" { - return nil, fmt.Errorf("abi: purely underscored output cannot unpack to struct") + return nil, errors.New("abi: purely underscored output cannot unpack to struct") } // this abi has already been paired, skip it... unless there exists another, yet unassigned diff --git a/accounts/abi/selector_parser.go b/accounts/abi/selector_parser.go index d5472e374f..b8ddd7d656 100644 --- a/accounts/abi/selector_parser.go +++ b/accounts/abi/selector_parser.go @@ -17,6 +17,7 @@ package abi import ( + "errors" "fmt" ) @@ -40,7 +41,7 @@ func isIdentifierSymbol(c byte) bool { func parseToken(unescapedSelector string, isIdent bool) (string, string, error) { if len(unescapedSelector) == 0 { - return "", "", fmt.Errorf("empty token") + return "", "", errors.New("empty token") } firstChar := unescapedSelector[0] position := 1 @@ -110,7 +111,7 @@ func parseCompositeType(unescapedSelector string) ([]interface{}, string, error) func parseType(unescapedSelector string) (interface{}, string, error) { if len(unescapedSelector) == 0 { - return nil, "", fmt.Errorf("empty type") + return nil, "", errors.New("empty type") } if unescapedSelector[0] == '(' { return parseCompositeType(unescapedSelector) diff --git a/accounts/abi/type.go b/accounts/abi/type.go index 7f74907a84..2eee11787f 100644 --- a/accounts/abi/type.go +++ b/accounts/abi/type.go @@ -70,7 +70,7 @@ var ( func NewType(t string, internalType string, components []ArgumentMarshaling) (typ Type, err error) { // check that array brackets are equal if they exist if strings.Count(t, "[") != strings.Count(t, "]") { - return Type{}, fmt.Errorf("invalid arg type in abi") + return Type{}, errors.New("invalid arg type in abi") } typ.stringKind = t @@ -109,7 +109,7 @@ func NewType(t string, internalType string, components []ArgumentMarshaling) (ty } typ.stringKind = embeddedType.stringKind + sliced } else { - return Type{}, fmt.Errorf("invalid formatting of array type") + return Type{}, errors.New("invalid formatting of array type") } return typ, err } @@ -348,7 +348,7 @@ func (t Type) pack(v reflect.Value) ([]byte, error) { } } -// requireLengthPrefix returns whether the type requires any sort of length +// requiresLengthPrefix returns whether the type requires any sort of length // prefixing. func (t Type) requiresLengthPrefix() bool { return t.T == StringTy || t.T == BytesTy || t.T == SliceTy diff --git a/accounts/abi/unpack.go b/accounts/abi/unpack.go index 1e778a6ff0..905b5ce629 100644 --- a/accounts/abi/unpack.go +++ b/accounts/abi/unpack.go @@ -18,6 +18,7 @@ package abi import ( "encoding/binary" + "errors" "fmt" "math" "math/big" @@ -125,7 +126,7 @@ func readBool(word []byte) (bool, error) { // readFunctionType enforces that standard by always presenting it as a 24-array (address + sig = 24 bytes) func readFunctionType(t Type, word []byte) (funcTy [24]byte, err error) { if t.T != FunctionTy { - return [24]byte{}, fmt.Errorf("abi: invalid type in call to make function type byte array") + return [24]byte{}, errors.New("abi: invalid type in call to make function type byte array") } if garbage := binary.BigEndian.Uint64(word[24:32]); garbage != 0 { err = fmt.Errorf("abi: got improperly encoded function type, got %v", word) @@ -138,7 +139,7 @@ func readFunctionType(t Type, word []byte) (funcTy [24]byte, err error) { // ReadFixedBytes uses reflection to create a fixed array to be read from. func ReadFixedBytes(t Type, word []byte) (interface{}, error) { if t.T != FixedBytesTy { - return nil, fmt.Errorf("abi: invalid type in call to make fixed byte array") + return nil, errors.New("abi: invalid type in call to make fixed byte array") } // convert array := reflect.New(t.GetType()).Elem() @@ -159,14 +160,15 @@ func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error) // this value will become our slice or our array, depending on the type var refSlice reflect.Value - if t.T == SliceTy { + switch t.T { + case SliceTy: // declare our slice refSlice = reflect.MakeSlice(t.GetType(), size, size) - } else if t.T == ArrayTy { + case ArrayTy: // declare our array refSlice = reflect.New(t.GetType()).Elem() - } else { - return nil, fmt.Errorf("abi: invalid type in array/slice unpacking stage") + default: + return nil, errors.New("abi: invalid type in array/slice unpacking stage") } // Arrays have packed elements, resulting in longer unpack steps. diff --git a/accounts/external/backend.go b/accounts/external/backend.go index d403b7e562..6f1581f9b8 100644 --- a/accounts/external/backend.go +++ b/accounts/external/backend.go @@ -17,6 +17,7 @@ package external import ( + "errors" "fmt" "math/big" "sync" @@ -98,11 +99,11 @@ func (api *ExternalSigner) Status() (string, error) { } func (api *ExternalSigner) Open(passphrase string) error { - return fmt.Errorf("operation not supported on external signers") + return errors.New("operation not supported on external signers") } func (api *ExternalSigner) Close() error { - return fmt.Errorf("operation not supported on external signers") + return errors.New("operation not supported on external signers") } func (api *ExternalSigner) Accounts() []accounts.Account { @@ -145,7 +146,7 @@ func (api *ExternalSigner) Contains(account accounts.Account) bool { } func (api *ExternalSigner) Derive(path accounts.DerivationPath, pin bool) (accounts.Account, error) { - return accounts.Account{}, fmt.Errorf("operation not supported on external signers") + return accounts.Account{}, errors.New("operation not supported on external signers") } func (api *ExternalSigner) SelfDerive(bases []accounts.DerivationPath, chain ethereum.ChainStateReader) { @@ -242,14 +243,14 @@ func (api *ExternalSigner) SignTx(account accounts.Account, tx *types.Transactio } func (api *ExternalSigner) SignTextWithPassphrase(account accounts.Account, passphrase string, text []byte) ([]byte, error) { - return []byte{}, fmt.Errorf("password-operations not supported on external signers") + return []byte{}, errors.New("password-operations not supported on external signers") } func (api *ExternalSigner) SignTxWithPassphrase(account accounts.Account, passphrase string, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) { - return nil, fmt.Errorf("password-operations not supported on external signers") + return nil, errors.New("password-operations not supported on external signers") } func (api *ExternalSigner) SignDataWithPassphrase(account accounts.Account, passphrase, mimeType string, data []byte) ([]byte, error) { - return nil, fmt.Errorf("password-operations not supported on external signers") + return nil, errors.New("password-operations not supported on external signers") } func (api *ExternalSigner) listAccounts() ([]common.Address, error) { diff --git a/accounts/keystore/account_cache.go b/accounts/keystore/account_cache.go index 12f92d2619..4ed1439514 100644 --- a/accounts/keystore/account_cache.go +++ b/accounts/keystore/account_cache.go @@ -31,6 +31,7 @@ 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 @@ -38,11 +39,10 @@ import ( // exist yet, the code will attempt to create a watcher at most this often. const minReloadInterval = 2 * time.Second -type accountsByURL []accounts.Account - -func (s accountsByURL) Len() int { return len(s) } -func (s accountsByURL) Less(i, j int) bool { return s[i].URL.Cmp(s[j].URL) < 0 } -func (s accountsByURL) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +// byURL defines the sorting order for accounts. +func byURL(a, b accounts.Account) int { + return a.URL.Cmp(b.URL) +} // AmbiguousAddrError is returned when attempting to unlock // an address for which more than one file exists. @@ -67,7 +67,7 @@ type accountCache struct { keydir string watcher *watcher mu sync.Mutex - all accountsByURL + all []accounts.Account byAddr map[common.Address][]accounts.Account throttle *time.Timer notify chan struct{} @@ -194,7 +194,7 @@ func (ac *accountCache) find(a accounts.Account) (accounts.Account, error) { default: err := &AmbiguousAddrError{Addr: a.Address, Matches: make([]accounts.Account, len(matches))} copy(err.Matches, matches) - sort.Sort(accountsByURL(err.Matches)) + slices.SortFunc(err.Matches, byURL) return accounts.Account{}, err } } diff --git a/accounts/keystore/account_cache_test.go b/accounts/keystore/account_cache_test.go index aa71c12018..3847e9daf6 100644 --- a/accounts/keystore/account_cache_test.go +++ b/accounts/keystore/account_cache_test.go @@ -17,12 +17,12 @@ package keystore import ( + "errors" "fmt" "math/rand" "os" "path/filepath" "reflect" - "sort" "testing" "time" @@ -30,6 +30,7 @@ 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 ( @@ -74,7 +75,7 @@ func waitForAccounts(wantAccounts []accounts.Account, ks *KeyStore) error { select { case <-ks.changes: default: - return fmt.Errorf("wasn't notified of new accounts") + return errors.New("wasn't notified of new accounts") } return nil } @@ -202,7 +203,7 @@ func TestCacheAddDeleteOrder(t *testing.T) { // Check that the account list is sorted by filename. wantAccounts := make([]accounts.Account, len(accs)) copy(wantAccounts, accs) - sort.Sort(accountsByURL(wantAccounts)) + slices.SortFunc(wantAccounts, byURL) list := cache.accounts() if !reflect.DeepEqual(list, wantAccounts) { t.Fatalf("got accounts: %s\nwant %s", spew.Sdump(accs), spew.Sdump(wantAccounts)) diff --git a/accounts/keystore/keystore_test.go b/accounts/keystore/keystore_test.go index f90d809b55..deb7cae9f9 100644 --- a/accounts/keystore/keystore_test.go +++ b/accounts/keystore/keystore_test.go @@ -20,7 +20,6 @@ import ( "math/rand" "os" "runtime" - "sort" "strings" "sync" "sync/atomic" @@ -31,6 +30,7 @@ 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) @@ -397,19 +397,19 @@ func TestImportRace(t *testing.T) { t.Fatalf("failed to export account: %v", acc) } _, ks2 := tmpKeyStore(t, true) - var atom uint32 + var atom atomic.Uint32 var wg sync.WaitGroup wg.Add(2) for i := 0; i < 2; i++ { go func() { defer wg.Done() if _, err := ks2.Import(json, "new", "new"); err != nil { - atomic.AddUint32(&atom, 1) + atom.Add(1) } }() } wg.Wait() - if atom != 1 { + if atom.Load() != 1 { t.Errorf("Import is racy") } } @@ -424,7 +424,7 @@ func checkAccounts(t *testing.T, live map[common.Address]accounts.Account, walle for _, account := range live { liveList = append(liveList, account) } - sort.Sort(accountsByURL(liveList)) + slices.SortFunc(liveList, byURL) for j, wallet := range wallets { if accs := wallet.Accounts(); len(accs) != 1 { t.Errorf("wallet %d: contains invalid number of accounts: have %d, want 1", j, len(accs)) diff --git a/accounts/keystore/passphrase.go b/accounts/keystore/passphrase.go index 1701fbf536..8d6ed2b14e 100644 --- a/accounts/keystore/passphrase.go +++ b/accounts/keystore/passphrase.go @@ -225,10 +225,13 @@ func DecryptKey(keyjson []byte, auth string) (*Key, error) { if err != nil { return nil, err } - key := crypto.ToECDSAUnsafe(keyBytes) + key, err := crypto.ToECDSA(keyBytes) + if err != nil { + return nil, fmt.Errorf("invalid key: %w", err) + } id, err := uuid.FromBytes(keyId) if err != nil { - return nil, err + return nil, fmt.Errorf("invalid UUID: %w", err) } return &Key{ Id: id, diff --git a/accounts/scwallet/securechannel.go b/accounts/scwallet/securechannel.go index b1b533eb72..bbd8b22647 100644 --- a/accounts/scwallet/securechannel.go +++ b/accounts/scwallet/securechannel.go @@ -24,6 +24,7 @@ import ( "crypto/rand" "crypto/sha256" "crypto/sha512" + "errors" "fmt" "github.com/ethereum/go-ethereum/crypto" @@ -125,7 +126,7 @@ func (s *SecureChannelSession) Pair(pairingPassword []byte) error { // Unpair disestablishes an existing pairing. func (s *SecureChannelSession) Unpair() error { if s.PairingKey == nil { - return fmt.Errorf("cannot unpair: not paired") + return errors.New("cannot unpair: not paired") } _, err := s.transmitEncrypted(claSCWallet, insUnpair, s.PairingIndex, 0, []byte{}) @@ -141,7 +142,7 @@ func (s *SecureChannelSession) Unpair() error { // Open initializes the secure channel. func (s *SecureChannelSession) Open() error { if s.iv != nil { - return fmt.Errorf("session already opened") + return errors.New("session already opened") } response, err := s.open() @@ -215,7 +216,7 @@ func (s *SecureChannelSession) pair(p1 uint8, data []byte) (*responseAPDU, error // transmitEncrypted sends an encrypted message, and decrypts and returns the response. func (s *SecureChannelSession) transmitEncrypted(cla, ins, p1, p2 byte, data []byte) (*responseAPDU, error) { if s.iv == nil { - return nil, fmt.Errorf("channel not open") + return nil, errors.New("channel not open") } data, err := s.encryptAPDU(data) @@ -254,7 +255,7 @@ func (s *SecureChannelSession) transmitEncrypted(cla, ins, p1, p2 byte, data []b return nil, err } if !bytes.Equal(s.iv, rmac) { - return nil, fmt.Errorf("invalid MAC in response") + return nil, errors.New("invalid MAC in response") } rapdu := &responseAPDU{} @@ -319,7 +320,7 @@ func unpad(data []byte, terminator byte) ([]byte, error) { return nil, fmt.Errorf("expected end of padding, got %d", data[len(data)-i]) } } - return nil, fmt.Errorf("expected end of padding, got 0") + return nil, errors.New("expected end of padding, got 0") } // updateIV is an internal method that updates the initialization vector after diff --git a/accounts/scwallet/wallet.go b/accounts/scwallet/wallet.go index 6a40e28ae6..067bda83f1 100644 --- a/accounts/scwallet/wallet.go +++ b/accounts/scwallet/wallet.go @@ -252,7 +252,7 @@ func (w *Wallet) release() error { // with the wallet. func (w *Wallet) pair(puk []byte) error { if w.session.paired() { - return fmt.Errorf("wallet already paired") + return errors.New("wallet already paired") } pairing, err := w.session.pair(puk) if err != nil { @@ -813,7 +813,7 @@ func (s *Session) pair(secret []byte) (smartcardPairing, error) { // unpair deletes an existing pairing. func (s *Session) unpair() error { if !s.verified { - return fmt.Errorf("unpair requires that the PIN be verified") + return errors.New("unpair requires that the PIN be verified") } return s.Channel.Unpair() } @@ -907,7 +907,7 @@ func (s *Session) initialize(seed []byte) error { return err } if status == "Online" { - return fmt.Errorf("card is already initialized, cowardly refusing to proceed") + return errors.New("card is already initialized, cowardly refusing to proceed") } s.Wallet.lock.Lock() diff --git a/accounts/usbwallet/hub.go b/accounts/usbwallet/hub.go index 2139967228..e67942dbc1 100644 --- a/accounts/usbwallet/hub.go +++ b/accounts/usbwallet/hub.go @@ -63,9 +63,9 @@ type Hub struct { stateLock sync.RWMutex // Protects the internals of the hub from racey access // TODO(karalabe): remove if hotplug lands on Windows - commsPend int // Number of operations blocking enumeration - commsLock sync.Mutex // Lock protecting the pending counter and enumeration - enumFails uint32 // Number of times enumeration has failed + commsPend int // Number of operations blocking enumeration + commsLock sync.Mutex // Lock protecting the pending counter and enumeration + enumFails atomic.Uint32 // Number of times enumeration has failed } // NewLedgerHub creates a new hardware wallet manager for Ledger devices. @@ -151,7 +151,7 @@ func (hub *Hub) refreshWallets() { return } // If USB enumeration is continually failing, don't keep trying indefinitely - if atomic.LoadUint32(&hub.enumFails) > 2 { + if hub.enumFails.Load() > 2 { return } // Retrieve the current list of USB wallet devices @@ -172,7 +172,7 @@ func (hub *Hub) refreshWallets() { } infos, err := usb.Enumerate(hub.vendorID, 0) if err != nil { - failcount := atomic.AddUint32(&hub.enumFails, 1) + failcount := hub.enumFails.Add(1) if runtime.GOOS == "linux" { // See rationale before the enumeration why this is needed and only on Linux. hub.commsLock.Unlock() @@ -181,7 +181,7 @@ func (hub *Hub) refreshWallets() { "vendor", hub.vendorID, "failcount", failcount, "err", err) return } - atomic.StoreUint32(&hub.enumFails, 0) + hub.enumFails.Store(0) for _, info := range infos { for _, id := range hub.productIDs { diff --git a/accounts/usbwallet/wallet.go b/accounts/usbwallet/wallet.go index 0e399a6d09..05add081ab 100644 --- a/accounts/usbwallet/wallet.go +++ b/accounts/usbwallet/wallet.go @@ -624,7 +624,7 @@ func (w *wallet) SignTx(account accounts.Account, tx *types.Transaction, chainID return signed, nil } -// SignHashWithPassphrase implements accounts.Wallet, however signing arbitrary +// SignTextWithPassphrase implements accounts.Wallet, however signing arbitrary // data is not supported for Ledger wallets, so this method will always return // an error. func (w *wallet) SignTextWithPassphrase(account accounts.Account, passphrase string, text []byte) ([]byte, error) { diff --git a/beacon/engine/errors.go b/beacon/engine/errors.go index 769001b9e3..62773a0ea9 100644 --- a/beacon/engine/errors.go +++ b/beacon/engine/errors.go @@ -80,6 +80,7 @@ var ( InvalidPayloadAttributes = &EngineAPIError{code: -38003, msg: "Invalid payload attributes"} TooLargeRequest = &EngineAPIError{code: -38004, msg: "Too large request"} InvalidParams = &EngineAPIError{code: -32602, msg: "Invalid parameters"} + UnsupportedFork = &EngineAPIError{code: -38005, msg: "Unsupported fork"} STATUS_INVALID = ForkChoiceResponse{PayloadStatus: PayloadStatusV1{Status: INVALID}, PayloadID: nil} STATUS_SYNCING = ForkChoiceResponse{PayloadStatus: PayloadStatusV1{Status: SYNCING}, PayloadID: nil} diff --git a/beacon/engine/gen_blockparams.go b/beacon/engine/gen_blockparams.go index 0dd2b52597..b1f01b50ff 100644 --- a/beacon/engine/gen_blockparams.go +++ b/beacon/engine/gen_blockparams.go @@ -20,12 +20,14 @@ func (p PayloadAttributes) MarshalJSON() ([]byte, error) { Random common.Hash `json:"prevRandao" gencodec:"required"` SuggestedFeeRecipient common.Address `json:"suggestedFeeRecipient" gencodec:"required"` Withdrawals []*types.Withdrawal `json:"withdrawals"` + BeaconRoot *common.Hash `json:"parentBeaconBlockRoot"` } var enc PayloadAttributes enc.Timestamp = hexutil.Uint64(p.Timestamp) enc.Random = p.Random enc.SuggestedFeeRecipient = p.SuggestedFeeRecipient enc.Withdrawals = p.Withdrawals + enc.BeaconRoot = p.BeaconRoot return json.Marshal(&enc) } @@ -36,6 +38,7 @@ func (p *PayloadAttributes) UnmarshalJSON(input []byte) error { Random *common.Hash `json:"prevRandao" gencodec:"required"` SuggestedFeeRecipient *common.Address `json:"suggestedFeeRecipient" gencodec:"required"` Withdrawals []*types.Withdrawal `json:"withdrawals"` + BeaconRoot *common.Hash `json:"parentBeaconBlockRoot"` } var dec PayloadAttributes if err := json.Unmarshal(input, &dec); err != nil { @@ -56,5 +59,8 @@ func (p *PayloadAttributes) UnmarshalJSON(input []byte) error { if dec.Withdrawals != nil { p.Withdrawals = dec.Withdrawals } + if dec.BeaconRoot != nil { + p.BeaconRoot = dec.BeaconRoot + } return nil } diff --git a/beacon/engine/gen_ed.go b/beacon/engine/gen_ed.go index 336dfc6cc7..6893d64a16 100644 --- a/beacon/engine/gen_ed.go +++ b/beacon/engine/gen_ed.go @@ -32,6 +32,8 @@ func (e ExecutableData) MarshalJSON() ([]byte, error) { 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"` } var enc ExecutableData enc.ParentHash = e.ParentHash @@ -54,6 +56,8 @@ func (e ExecutableData) MarshalJSON() ([]byte, error) { } } enc.Withdrawals = e.Withdrawals + enc.BlobGasUsed = (*hexutil.Uint64)(e.BlobGasUsed) + enc.ExcessBlobGas = (*hexutil.Uint64)(e.ExcessBlobGas) return json.Marshal(&enc) } @@ -75,6 +79,8 @@ func (e *ExecutableData) UnmarshalJSON(input []byte) error { 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"` } var dec ExecutableData if err := json.Unmarshal(input, &dec); err != nil { @@ -142,5 +148,11 @@ func (e *ExecutableData) UnmarshalJSON(input []byte) error { if dec.Withdrawals != nil { e.Withdrawals = dec.Withdrawals } + if dec.BlobGasUsed != nil { + e.BlobGasUsed = (*uint64)(dec.BlobGasUsed) + } + if dec.ExcessBlobGas != nil { + e.ExcessBlobGas = (*uint64)(dec.ExcessBlobGas) + } return nil } diff --git a/beacon/engine/gen_epe.go b/beacon/engine/gen_epe.go index cc66cef6cd..e69f9a5951 100644 --- a/beacon/engine/gen_epe.go +++ b/beacon/engine/gen_epe.go @@ -17,10 +17,14 @@ func (e ExecutionPayloadEnvelope) MarshalJSON() ([]byte, error) { type ExecutionPayloadEnvelope struct { ExecutionPayload *ExecutableData `json:"executionPayload" gencodec:"required"` BlockValue *hexutil.Big `json:"blockValue" gencodec:"required"` + BlobsBundle *BlobsBundleV1 `json:"blobsBundle"` + Override bool `json:"shouldOverrideBuilder"` } var enc ExecutionPayloadEnvelope enc.ExecutionPayload = e.ExecutionPayload enc.BlockValue = (*hexutil.Big)(e.BlockValue) + enc.BlobsBundle = e.BlobsBundle + enc.Override = e.Override return json.Marshal(&enc) } @@ -29,6 +33,8 @@ func (e *ExecutionPayloadEnvelope) UnmarshalJSON(input []byte) error { type ExecutionPayloadEnvelope struct { ExecutionPayload *ExecutableData `json:"executionPayload" gencodec:"required"` BlockValue *hexutil.Big `json:"blockValue" gencodec:"required"` + BlobsBundle *BlobsBundleV1 `json:"blobsBundle"` + Override *bool `json:"shouldOverrideBuilder"` } var dec ExecutionPayloadEnvelope if err := json.Unmarshal(input, &dec); err != nil { @@ -42,5 +48,11 @@ func (e *ExecutionPayloadEnvelope) UnmarshalJSON(input []byte) error { return errors.New("missing required field 'blockValue' for ExecutionPayloadEnvelope") } e.BlockValue = (*big.Int)(dec.BlockValue) + if dec.BlobsBundle != nil { + e.BlobsBundle = dec.BlobsBundle + } + if dec.Override != nil { + e.Override = *dec.Override + } return nil } diff --git a/beacon/engine/types.go b/beacon/engine/types.go index 07ebe544b4..67f30d4455 100644 --- a/beacon/engine/types.go +++ b/beacon/engine/types.go @@ -35,6 +35,7 @@ type PayloadAttributes struct { Random common.Hash `json:"prevRandao" gencodec:"required"` SuggestedFeeRecipient common.Address `json:"suggestedFeeRecipient" gencodec:"required"` Withdrawals []*types.Withdrawal `json:"withdrawals"` + BeaconRoot *common.Hash `json:"parentBeaconBlockRoot"` } // JSON type overrides for PayloadAttributes. @@ -61,6 +62,8 @@ type ExecutableData struct { 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"` } // JSON type overrides for executableData. @@ -73,6 +76,8 @@ type executableDataMarshaling struct { ExtraData hexutil.Bytes LogsBloom hexutil.Bytes Transactions []hexutil.Bytes + BlobGasUsed *hexutil.Uint64 + ExcessBlobGas *hexutil.Uint64 } //go:generate go run github.com/fjl/gencodec -type ExecutionPayloadEnvelope -field-override executionPayloadEnvelopeMarshaling -out gen_epe.go @@ -80,6 +85,14 @@ type executableDataMarshaling struct { type ExecutionPayloadEnvelope struct { ExecutionPayload *ExecutableData `json:"executionPayload" gencodec:"required"` BlockValue *big.Int `json:"blockValue" gencodec:"required"` + BlobsBundle *BlobsBundleV1 `json:"blobsBundle"` + Override bool `json:"shouldOverrideBuilder"` +} + +type BlobsBundleV1 struct { + Commitments []hexutil.Bytes `json:"commitments"` + Proofs []hexutil.Bytes `json:"proofs"` + Blobs []hexutil.Bytes `json:"blobs"` } // JSON type overrides for ExecutionPayloadEnvelope. @@ -152,14 +165,15 @@ func decodeTransactions(enc [][]byte) ([]*types.Transaction, error) { // ExecutableDataToBlock constructs a block from executable data. // It verifies that the following fields: // -// len(extraData) <= 32 -// uncleHash = emptyUncleHash -// difficulty = 0 +// len(extraData) <= 32 +// uncleHash = emptyUncleHash +// difficulty = 0 +// if versionedHashes != nil, versionedHashes match to blob transactions // // 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) (*types.Block, error) { +func ExecutableDataToBlock(params ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash) (*types.Block, error) { txs, err := decodeTransactions(params.Transactions) if err != nil { return nil, err @@ -174,6 +188,18 @@ func ExecutableDataToBlock(params ExecutableData) (*types.Block, error) { 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 + for _, tx := range txs { + blobHashes = append(blobHashes, tx.BlobHashes()...) + } + if len(blobHashes) != len(versionedHashes) { + return nil, fmt.Errorf("invalid number of versionedHashes: %v blobHashes: %v", versionedHashes, blobHashes) + } + for i := 0; i < len(blobHashes); i++ { + if blobHashes[i] != versionedHashes[i] { + return nil, fmt.Errorf("invalid versionedHash at %v: %v blobHashes: %v", i, versionedHashes, blobHashes) + } + } // Only set withdrawalsRoot if it is non-nil. This allows CLs to use // ExecutableData before withdrawals are enabled by marshaling // Withdrawals as the json null value. @@ -183,22 +209,25 @@ func ExecutableDataToBlock(params ExecutableData) (*types.Block, error) { withdrawalsRoot = &h } header := &types.Header{ - ParentHash: params.ParentHash, - UncleHash: types.EmptyUncleHash, - Coinbase: params.FeeRecipient, - Root: params.StateRoot, - TxHash: types.DeriveSha(types.Transactions(txs), trie.NewStackTrie(nil)), - ReceiptHash: params.ReceiptsRoot, - Bloom: types.BytesToBloom(params.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, - WithdrawalsHash: withdrawalsRoot, + ParentHash: params.ParentHash, + UncleHash: types.EmptyUncleHash, + Coinbase: params.FeeRecipient, + Root: params.StateRoot, + TxHash: types.DeriveSha(types.Transactions(txs), trie.NewStackTrie(nil)), + ReceiptHash: params.ReceiptsRoot, + Bloom: types.BytesToBloom(params.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, + WithdrawalsHash: withdrawalsRoot, + ExcessBlobGas: params.ExcessBlobGas, + BlobGasUsed: params.BlobGasUsed, + ParentBeaconRoot: beaconRoot, } block := types.NewBlockWithHeader(header).WithBody(txs, nil /* uncles */).WithWithdrawals(params.Withdrawals) if block.Hash() != params.BlockHash { @@ -209,7 +238,7 @@ func ExecutableDataToBlock(params ExecutableData) (*types.Block, error) { // BlockToExecutableData constructs the ExecutableData structure by filling the // fields from the given block. It assumes the given block is post-merge block. -func BlockToExecutableData(block *types.Block, fees *big.Int) *ExecutionPayloadEnvelope { +func BlockToExecutableData(block *types.Block, fees *big.Int, sidecars []*types.BlobTxSidecar) *ExecutionPayloadEnvelope { data := &ExecutableData{ BlockHash: block.Hash(), ParentHash: block.ParentHash(), @@ -226,8 +255,22 @@ func BlockToExecutableData(block *types.Block, fees *big.Int) *ExecutionPayloadE Random: block.MixDigest(), ExtraData: block.Extra(), Withdrawals: block.Withdrawals(), + BlobGasUsed: block.BlobGasUsed(), + ExcessBlobGas: block.ExcessBlobGas(), } - return &ExecutionPayloadEnvelope{ExecutionPayload: data, BlockValue: fees} + bundle := BlobsBundleV1{ + Commitments: make([]hexutil.Bytes, 0), + Blobs: make([]hexutil.Bytes, 0), + Proofs: make([]hexutil.Bytes, 0), + } + for _, sidecar := range sidecars { + for j := range sidecar.Blobs { + bundle.Blobs = append(bundle.Blobs, hexutil.Bytes(sidecar.Blobs[j][:])) + bundle.Commitments = append(bundle.Commitments, hexutil.Bytes(sidecar.Commitments[j][:])) + bundle.Proofs = append(bundle.Proofs, hexutil.Bytes(sidecar.Proofs[j][:])) + } + } + return &ExecutionPayloadEnvelope{ExecutionPayload: data, BlockValue: fees, BlobsBundle: &bundle, Override: false} } // ExecutionPayloadBodyV1 is used in the response to GetPayloadBodiesByHashV1 and GetPayloadBodiesByRangeV1 diff --git a/beacon/merkle/merkle.go b/beacon/merkle/merkle.go new file mode 100644 index 0000000000..30896f9b01 --- /dev/null +++ b/beacon/merkle/merkle.go @@ -0,0 +1,67 @@ +// 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 merkle implements proof verifications in binary merkle trees. +package merkle + +import ( + "crypto/sha256" + "errors" + "reflect" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" +) + +// Value represents either a 32 byte leaf value or hash node in a binary merkle tree/partial proof. +type Value [32]byte + +// Values represent a series of merkle tree leaves/nodes. +type Values []Value + +var valueT = reflect.TypeOf(Value{}) + +// UnmarshalJSON parses a merkle value in hex syntax. +func (m *Value) UnmarshalJSON(input []byte) error { + return hexutil.UnmarshalFixedJSON(valueT, input, m[:]) +} + +// VerifyProof verifies a Merkle proof branch for a single value in a +// binary Merkle tree (index is a generalized tree index). +func VerifyProof(root common.Hash, index uint64, branch Values, value Value) error { + hasher := sha256.New() + for _, sibling := range branch { + hasher.Reset() + if index&1 == 0 { + hasher.Write(value[:]) + hasher.Write(sibling[:]) + } else { + hasher.Write(sibling[:]) + hasher.Write(value[:]) + } + hasher.Sum(value[:0]) + if index >>= 1; index == 0 { + return errors.New("branch has extra items") + } + } + if index != 1 { + return errors.New("branch is missing items") + } + if common.Hash(value) != root { + return errors.New("root mismatch") + } + return nil +} diff --git a/core/state/snapshot/sort.go b/beacon/params/params.go similarity index 51% rename from core/state/snapshot/sort.go rename to beacon/params/params.go index 88841231d9..ee9feb1acb 100644 --- a/core/state/snapshot/sort.go +++ b/beacon/params/params.go @@ -1,4 +1,4 @@ -// Copyright 2019 The go-ethereum Authors +// 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 @@ -14,23 +14,31 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package snapshot +package params -import ( - "bytes" +const ( + EpochLength = 32 + SyncPeriodLength = 8192 - "github.com/ethereum/go-ethereum/common" + BLSSignatureSize = 96 + BLSPubkeySize = 48 + + SyncCommitteeSize = 512 + SyncCommitteeBitmaskSize = SyncCommitteeSize / 8 + SyncCommitteeSupermajority = (SyncCommitteeSize*2 + 2) / 3 ) -// hashes is a helper to implement sort.Interface. -type hashes []common.Hash - -// Len is the number of elements in the collection. -func (hs hashes) Len() int { return len(hs) } - -// Less reports whether the element with index i should sort before the element -// with index j. -func (hs hashes) Less(i, j int) bool { return bytes.Compare(hs[i][:], hs[j][:]) < 0 } - -// Swap swaps the elements with indexes i and j. -func (hs hashes) Swap(i, j int) { hs[i], hs[j] = hs[j], hs[i] } +const ( + StateIndexGenesisTime = 32 + StateIndexGenesisValidators = 33 + StateIndexForkVersion = 141 + StateIndexLatestHeader = 36 + StateIndexBlockRoots = 37 + StateIndexStateRoots = 38 + StateIndexHistoricRoots = 39 + StateIndexFinalBlock = 105 + StateIndexSyncCommittee = 54 + StateIndexNextSyncCommittee = 55 + StateIndexExecPayload = 56 + StateIndexExecHead = 908 +) diff --git a/beacon/types/committee.go b/beacon/types/committee.go new file mode 100644 index 0000000000..5f89c27554 --- /dev/null +++ b/beacon/types/committee.go @@ -0,0 +1,191 @@ +// 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 types + +import ( + "crypto/sha256" + "encoding/json" + "fmt" + "math/bits" + + "github.com/ethereum/go-ethereum/beacon/params" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + bls "github.com/protolambda/bls12-381-util" +) + +// SerializedSyncCommitteeSize is the size of the sync committee plus the +// aggregate public key. +const SerializedSyncCommitteeSize = (params.SyncCommitteeSize + 1) * params.BLSPubkeySize + +// SerializedSyncCommittee is the serialized version of a sync committee +// plus the aggregate public key. +type SerializedSyncCommittee [SerializedSyncCommitteeSize]byte + +// jsonSyncCommittee is the JSON representation of a sync committee. +// +// See data structure definition here: +// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/beacon-chain.md#syncaggregate +type jsonSyncCommittee struct { + Pubkeys []hexutil.Bytes `json:"pubkeys"` + Aggregate hexutil.Bytes `json:"aggregate_pubkey"` +} + +// MarshalJSON implements json.Marshaler. +func (s *SerializedSyncCommittee) MarshalJSON() ([]byte, error) { + sc := jsonSyncCommittee{Pubkeys: make([]hexutil.Bytes, params.SyncCommitteeSize)} + for i := range sc.Pubkeys { + sc.Pubkeys[i] = make(hexutil.Bytes, params.BLSPubkeySize) + copy(sc.Pubkeys[i][:], s[i*params.BLSPubkeySize:(i+1)*params.BLSPubkeySize]) + } + sc.Aggregate = make(hexutil.Bytes, params.BLSPubkeySize) + copy(sc.Aggregate[:], s[params.SyncCommitteeSize*params.BLSPubkeySize:]) + return json.Marshal(&sc) +} + +// UnmarshalJSON implements json.Marshaler. +func (s *SerializedSyncCommittee) UnmarshalJSON(input []byte) error { + var sc jsonSyncCommittee + if err := json.Unmarshal(input, &sc); err != nil { + return err + } + if len(sc.Pubkeys) != params.SyncCommitteeSize { + return fmt.Errorf("invalid number of pubkeys %d", len(sc.Pubkeys)) + } + for i, key := range sc.Pubkeys { + if len(key) != params.BLSPubkeySize { + return fmt.Errorf("pubkey %d has invalid size %d", i, len(key)) + } + copy(s[i*params.BLSPubkeySize:], key[:]) + } + if len(sc.Aggregate) != params.BLSPubkeySize { + return fmt.Errorf("invalid aggregate pubkey size %d", len(sc.Aggregate)) + } + copy(s[params.SyncCommitteeSize*params.BLSPubkeySize:], sc.Aggregate[:]) + return nil +} + +// Root calculates the root hash of the binary tree representation of a sync +// committee provided in serialized format. +// +// TODO(zsfelfoldi): Get rid of this when SSZ encoding lands. +func (s *SerializedSyncCommittee) Root() common.Hash { + var ( + hasher = sha256.New() + padding [64 - params.BLSPubkeySize]byte + data [params.SyncCommitteeSize]common.Hash + l = params.SyncCommitteeSize + ) + for i := range data { + hasher.Reset() + hasher.Write(s[i*params.BLSPubkeySize : (i+1)*params.BLSPubkeySize]) + hasher.Write(padding[:]) + hasher.Sum(data[i][:0]) + } + for l > 1 { + for i := 0; i < l/2; i++ { + hasher.Reset() + hasher.Write(data[i*2][:]) + hasher.Write(data[i*2+1][:]) + hasher.Sum(data[i][:0]) + } + l /= 2 + } + hasher.Reset() + hasher.Write(s[SerializedSyncCommitteeSize-params.BLSPubkeySize : SerializedSyncCommitteeSize]) + hasher.Write(padding[:]) + hasher.Sum(data[1][:0]) + hasher.Reset() + hasher.Write(data[0][:]) + hasher.Write(data[1][:]) + hasher.Sum(data[0][:0]) + return data[0] +} + +// Deserialize splits open the pubkeys into proper BLS key types. +func (s *SerializedSyncCommittee) Deserialize() (*SyncCommittee, error) { + sc := new(SyncCommittee) + for i := 0; i <= params.SyncCommitteeSize; i++ { + key := new(bls.Pubkey) + + var bytes [params.BLSPubkeySize]byte + copy(bytes[:], s[i*params.BLSPubkeySize:(i+1)*params.BLSPubkeySize]) + + if err := key.Deserialize(&bytes); err != nil { + return nil, err + } + if i < params.SyncCommitteeSize { + sc.keys[i] = key + } else { + sc.aggregate = key + } + } + return sc, nil +} + +// SyncCommittee is a set of sync committee signer pubkeys and the aggregate key. +// +// See data structure definition here: +// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/beacon-chain.md#syncaggregate +type SyncCommittee struct { + keys [params.SyncCommitteeSize]*bls.Pubkey + aggregate *bls.Pubkey +} + +// VerifySignature returns true if the given sync aggregate is a valid signature +// or the given hash. +func (sc *SyncCommittee) VerifySignature(signingRoot common.Hash, signature *SyncAggregate) bool { + var ( + sig bls.Signature + keys = make([]*bls.Pubkey, 0, params.SyncCommitteeSize) + ) + if err := sig.Deserialize(&signature.Signature); err != nil { + return false + } + for i, key := range sc.keys { + if signature.Signers[i/8]&(byte(1)<<(i%8)) != 0 { + keys = append(keys, key) + } + } + return bls.FastAggregateVerify(keys, signingRoot[:], &sig) +} + +//go:generate go run github.com/fjl/gencodec -type SyncAggregate -field-override syncAggregateMarshaling -out gen_syncaggregate_json.go + +// SyncAggregate represents an aggregated BLS signature with Signers referring +// to a subset of the corresponding sync committee. +// +// See data structure definition here: +// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/beacon-chain.md#syncaggregate +type SyncAggregate struct { + Signers [params.SyncCommitteeBitmaskSize]byte `gencodec:"required" json:"sync_committee_bits"` + Signature [params.BLSSignatureSize]byte `gencodec:"required" json:"sync_committee_signature"` +} + +type syncAggregateMarshaling struct { + Signers hexutil.Bytes + Signature hexutil.Bytes +} + +// SignerCount returns the number of signers in the aggregate signature. +func (s *SyncAggregate) SignerCount() int { + var count int + for _, v := range s.Signers { + count += bits.OnesCount8(v) + } + return count +} diff --git a/beacon/types/config.go b/beacon/types/config.go new file mode 100644 index 0000000000..8cb8808b6f --- /dev/null +++ b/beacon/types/config.go @@ -0,0 +1,176 @@ +// 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 types + +import ( + "crypto/sha256" + "fmt" + "os" + "sort" + "strconv" + "strings" + + "github.com/ethereum/go-ethereum/beacon/merkle" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "gopkg.in/yaml.v3" +) + +// syncCommitteeDomain specifies the signatures specific use to avoid clashes +// across signing different data structures. +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 string + + // Epoch when given fork version is activated + Epoch uint64 + + // Fork version, see https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#custom-types + Version []byte + + // calculated by computeDomain, based on fork version and genesis validators root + domain merkle.Value +} + +// computeDomain returns the signature domain based on the given fork version +// and genesis validator set root. +func (f *Fork) computeDomain(genesisValidatorsRoot common.Hash) { + var ( + hasher = sha256.New() + forkVersion32 merkle.Value + forkDataRoot merkle.Value + ) + copy(forkVersion32[:], f.Version) + hasher.Write(forkVersion32[:]) + hasher.Write(genesisValidatorsRoot[:]) + hasher.Sum(forkDataRoot[:0]) + + f.domain[0] = syncCommitteeDomain + copy(f.domain[4:], forkDataRoot[:28]) +} + +// Forks is the list of all beacon chain forks in the chain configuration. +type Forks []*Fork + +// domain returns the signature domain for the given epoch (assumes that domains +// have already been calculated). +func (f Forks) domain(epoch uint64) (merkle.Value, error) { + for i := len(f) - 1; i >= 0; i-- { + if epoch >= f[i].Epoch { + return f[i].domain, nil + } + } + return merkle.Value{}, fmt.Errorf("unknown fork for epoch %d", epoch) +} + +// SigningRoot calculates the signing root of the given header. +func (f Forks) SigningRoot(header Header) (common.Hash, error) { + domain, err := f.domain(header.Epoch()) + if err != nil { + return common.Hash{}, err + } + var ( + signingRoot common.Hash + headerHash = header.Hash() + hasher = sha256.New() + ) + hasher.Write(headerHash[:]) + hasher.Write(domain[:]) + hasher.Sum(signingRoot[:0]) + + 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 } + +// ChainConfig contains the beacon chain configuration. +type ChainConfig struct { + GenesisTime uint64 // Unix timestamp of slot 0 + GenesisValidatorsRoot common.Hash // Root hash of the genesis validator set, used for signature domain calculation + Forks Forks +} + +// AddFork adds a new item to the list of forks. +func (c *ChainConfig) AddFork(name string, epoch uint64, version []byte) *ChainConfig { + fork := &Fork{ + Name: name, + Epoch: epoch, + Version: version, + } + fork.computeDomain(c.GenesisValidatorsRoot) + + c.Forks = append(c.Forks, fork) + sort.Sort(c.Forks) + + return c +} + +// LoadForks parses the beacon chain configuration file (config.yaml) and extracts +// the list of forks. +func (c *ChainConfig) LoadForks(path string) error { + file, err := os.ReadFile(path) + if err != nil { + return fmt.Errorf("failed to read beacon chain config file: %v", err) + } + config := make(map[string]string) + if err := yaml.Unmarshal(file, &config); err != nil { + return fmt.Errorf("failed to parse beacon chain config file: %v", err) + } + var ( + versions = make(map[string][]byte) + epochs = make(map[string]uint64) + ) + epochs["GENESIS"] = 0 + + for key, value := range config { + if strings.HasSuffix(key, "_FORK_VERSION") { + name := key[:len(key)-len("_FORK_VERSION")] + if v, err := hexutil.Decode(value); err == nil { + versions[name] = v + } else { + return fmt.Errorf("failed to decode hex fork id %q in beacon chain config file: %v", value, err) + } + } + if strings.HasSuffix(key, "_FORK_EPOCH") { + name := key[:len(key)-len("_FORK_EPOCH")] + if v, err := strconv.ParseUint(value, 10, 64); err == nil { + epochs[name] = v + } else { + return fmt.Errorf("failed to parse epoch number %q in beacon chain config file: %v", value, err) + } + } + } + for name, epoch := range epochs { + if version, ok := versions[name]; ok { + delete(versions, name) + c.AddFork(name, epoch, version) + } else { + return fmt.Errorf("fork id missing for %q in beacon chain config file", name) + } + } + 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 +} diff --git a/beacon/types/gen_header_json.go b/beacon/types/gen_header_json.go new file mode 100644 index 0000000000..9b3ffea06f --- /dev/null +++ b/beacon/types/gen_header_json.go @@ -0,0 +1,66 @@ +// Code generated by github.com/fjl/gencodec. DO NOT EDIT. + +package types + +import ( + "encoding/json" + "errors" + + "github.com/ethereum/go-ethereum/common" +) + +var _ = (*headerMarshaling)(nil) + +// MarshalJSON marshals as JSON. +func (h Header) MarshalJSON() ([]byte, error) { + type Header struct { + Slot common.Decimal `gencodec:"required" json:"slot"` + ProposerIndex common.Decimal `gencodec:"required" json:"proposer_index"` + ParentRoot common.Hash `gencodec:"required" json:"parent_root"` + StateRoot common.Hash `gencodec:"required" json:"state_root"` + BodyRoot common.Hash `gencodec:"required" json:"body_root"` + } + var enc Header + enc.Slot = common.Decimal(h.Slot) + enc.ProposerIndex = common.Decimal(h.ProposerIndex) + enc.ParentRoot = h.ParentRoot + enc.StateRoot = h.StateRoot + enc.BodyRoot = h.BodyRoot + return json.Marshal(&enc) +} + +// UnmarshalJSON unmarshals from JSON. +func (h *Header) UnmarshalJSON(input []byte) error { + type Header struct { + Slot *common.Decimal `gencodec:"required" json:"slot"` + ProposerIndex *common.Decimal `gencodec:"required" json:"proposer_index"` + ParentRoot *common.Hash `gencodec:"required" json:"parent_root"` + StateRoot *common.Hash `gencodec:"required" json:"state_root"` + BodyRoot *common.Hash `gencodec:"required" json:"body_root"` + } + var dec Header + if err := json.Unmarshal(input, &dec); err != nil { + return err + } + if dec.Slot == nil { + return errors.New("missing required field 'slot' for Header") + } + h.Slot = uint64(*dec.Slot) + if dec.ProposerIndex == nil { + return errors.New("missing required field 'proposer_index' for Header") + } + h.ProposerIndex = uint64(*dec.ProposerIndex) + if dec.ParentRoot == nil { + return errors.New("missing required field 'parent_root' for Header") + } + h.ParentRoot = *dec.ParentRoot + if dec.StateRoot == nil { + return errors.New("missing required field 'state_root' for Header") + } + h.StateRoot = *dec.StateRoot + if dec.BodyRoot == nil { + return errors.New("missing required field 'body_root' for Header") + } + h.BodyRoot = *dec.BodyRoot + return nil +} diff --git a/beacon/types/gen_syncaggregate_json.go b/beacon/types/gen_syncaggregate_json.go new file mode 100644 index 0000000000..1547ec5f01 --- /dev/null +++ b/beacon/types/gen_syncaggregate_json.go @@ -0,0 +1,51 @@ +// Code generated by github.com/fjl/gencodec. DO NOT EDIT. + +package types + +import ( + "encoding/json" + "errors" + + "github.com/ethereum/go-ethereum/common/hexutil" +) + +var _ = (*syncAggregateMarshaling)(nil) + +// MarshalJSON marshals as JSON. +func (s SyncAggregate) MarshalJSON() ([]byte, error) { + type SyncAggregate struct { + Signers hexutil.Bytes `gencodec:"required" json:"sync_committee_bits"` + Signature hexutil.Bytes `gencodec:"required" json:"sync_committee_signature"` + } + var enc SyncAggregate + enc.Signers = s.Signers[:] + enc.Signature = s.Signature[:] + return json.Marshal(&enc) +} + +// UnmarshalJSON unmarshals from JSON. +func (s *SyncAggregate) UnmarshalJSON(input []byte) error { + type SyncAggregate struct { + Signers *hexutil.Bytes `gencodec:"required" json:"sync_committee_bits"` + Signature *hexutil.Bytes `gencodec:"required" json:"sync_committee_signature"` + } + var dec SyncAggregate + if err := json.Unmarshal(input, &dec); err != nil { + return err + } + if dec.Signers == nil { + return errors.New("missing required field 'sync_committee_bits' for SyncAggregate") + } + if len(*dec.Signers) != len(s.Signers) { + return errors.New("field 'sync_committee_bits' has wrong length, need 64 items") + } + copy(s.Signers[:], *dec.Signers) + if dec.Signature == nil { + return errors.New("missing required field 'sync_committee_signature' for SyncAggregate") + } + if len(*dec.Signature) != len(s.Signature) { + return errors.New("field 'sync_committee_signature' has wrong length, need 96 items") + } + copy(s.Signature[:], *dec.Signature) + return nil +} diff --git a/beacon/types/header.go b/beacon/types/header.go new file mode 100644 index 0000000000..2ddc4575f1 --- /dev/null +++ b/beacon/types/header.go @@ -0,0 +1,121 @@ +// 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 types implements a few types of the beacon chain for light client usage. +package types + +import ( + "crypto/sha256" + "encoding/binary" + + "github.com/ethereum/go-ethereum/beacon/merkle" + "github.com/ethereum/go-ethereum/beacon/params" + "github.com/ethereum/go-ethereum/common" +) + +//go:generate go run github.com/fjl/gencodec -type Header -field-override headerMarshaling -out gen_header_json.go + +const ( + headerIndexSlot = 8 + headerIndexProposerIndex = 9 + headerIndexParentRoot = 10 + headerIndexStateRoot = 11 + headerIndexBodyRoot = 12 +) + +// Header defines a beacon header. +// +// See data structure definition here: +// https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#beaconblockheader +type Header struct { + // Monotonically increasing slot number for the beacon block (may be gapped) + Slot uint64 `gencodec:"required" json:"slot"` + + // Index into the validator table who created the beacon block + ProposerIndex uint64 `gencodec:"required" json:"proposer_index"` + + // SSZ hash of the parent beacon header + ParentRoot common.Hash `gencodec:"required" json:"parent_root"` + + // SSZ hash of the beacon state (https://github.com/ethereum/consensus-specs/blob/dev/specs/bellatrix/beacon-chain.md#beacon-state) + StateRoot common.Hash `gencodec:"required" json:"state_root"` + + // SSZ hash of the beacon block body (https://github.com/ethereum/consensus-specs/blob/dev/specs/bellatrix/beacon-chain.md#beaconblockbody) + BodyRoot common.Hash `gencodec:"required" json:"body_root"` +} + +// headerMarshaling is a field type overrides for gencodec. +type headerMarshaling struct { + Slot common.Decimal + ProposerIndex common.Decimal +} + +// Hash calculates the block root of the header. +// +// TODO(zsfelfoldi): Remove this when an SSZ encoder lands. +func (h *Header) Hash() common.Hash { + var values [16]merkle.Value // values corresponding to indices 8 to 15 of the beacon header tree + binary.LittleEndian.PutUint64(values[headerIndexSlot][:8], h.Slot) + binary.LittleEndian.PutUint64(values[headerIndexProposerIndex][:8], h.ProposerIndex) + values[headerIndexParentRoot] = merkle.Value(h.ParentRoot) + values[headerIndexStateRoot] = merkle.Value(h.StateRoot) + values[headerIndexBodyRoot] = merkle.Value(h.BodyRoot) + hasher := sha256.New() + for i := 7; i > 0; i-- { + hasher.Reset() + hasher.Write(values[i*2][:]) + hasher.Write(values[i*2+1][:]) + hasher.Sum(values[i][:0]) + } + return common.Hash(values[1]) +} + +// Epoch returns the epoch the header belongs to. +func (h *Header) Epoch() uint64 { + return h.Slot / params.EpochLength +} + +// SyncPeriod returns the sync period the header belongs to. +func (h *Header) SyncPeriod() uint64 { + return SyncPeriod(h.Slot) +} + +// SyncPeriodStart returns the first slot of the given period. +func SyncPeriodStart(period uint64) uint64 { + return period * params.SyncPeriodLength +} + +// SyncPeriod returns the sync period that the given slot belongs to. +func SyncPeriod(slot uint64) uint64 { + return slot / params.SyncPeriodLength +} + +// SignedHeader represents a beacon header signed by a sync committee. +// +// This structure is created from either an optimistic update or an instant update: +// - https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientoptimisticupdate +// - https://github.com/zsfelfoldi/beacon-APIs/blob/instant_update/apis/beacon/light_client/instant_update.yaml +type SignedHeader struct { + // Beacon header being signed + Header Header + + // 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 +} diff --git a/beacon/types/update.go b/beacon/types/update.go new file mode 100644 index 0000000000..06c1b61792 --- /dev/null +++ b/beacon/types/update.go @@ -0,0 +1,118 @@ +// 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 types + +import ( + "errors" + "fmt" + + "github.com/ethereum/go-ethereum/beacon/merkle" + "github.com/ethereum/go-ethereum/beacon/params" + "github.com/ethereum/go-ethereum/common" +) + +// LightClientUpdate is a proof of the next sync committee root based on a header +// signed by the sync committee of the given period. Optionally, the update can +// prove quasi-finality by the signed header referring to a previous, finalized +// header from the same period, and the finalized header referring to the next +// sync committee root. +// +// See data structure definition here: +// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientupdate +type LightClientUpdate struct { + AttestedHeader SignedHeader // Arbitrary header out of the period signed by the sync committee + NextSyncCommitteeRoot common.Hash // Sync committee of the next period advertised in the current one + NextSyncCommitteeBranch merkle.Values // Proof for the next period's sync committee + + FinalizedHeader *Header `rlp:"nil"` // Optional header to announce a point of finality + FinalityBranch merkle.Values // Proof for the announced finality + + score *UpdateScore // Weight of the update to compare between competing ones +} + +// Validate verifies the validity of the update. +func (update *LightClientUpdate) Validate() error { + period := update.AttestedHeader.Header.SyncPeriod() + if SyncPeriod(update.AttestedHeader.SignatureSlot) != period { + return errors.New("signature slot and signed header are from different periods") + } + if update.FinalizedHeader != nil { + if update.FinalizedHeader.SyncPeriod() != period { + return errors.New("finalized header is from different period") + } + if err := merkle.VerifyProof(update.AttestedHeader.Header.StateRoot, params.StateIndexFinalBlock, update.FinalityBranch, merkle.Value(update.FinalizedHeader.Hash())); err != nil { + return fmt.Errorf("invalid finalized header proof: %w", err) + } + } + if err := merkle.VerifyProof(update.AttestedHeader.Header.StateRoot, params.StateIndexNextSyncCommittee, update.NextSyncCommitteeBranch, merkle.Value(update.NextSyncCommitteeRoot)); err != nil { + return fmt.Errorf("invalid next sync committee proof: %w", err) + } + return nil +} + +// Score returns the UpdateScore describing the proof strength of the update +// Note: thread safety can be ensured by always calling Score on a newly received +// or decoded update before making it potentially available for other threads +func (update *LightClientUpdate) Score() UpdateScore { + if update.score == nil { + update.score = &UpdateScore{ + SignerCount: uint32(update.AttestedHeader.Signature.SignerCount()), + SubPeriodIndex: uint32(update.AttestedHeader.Header.Slot & 0x1fff), + FinalizedHeader: update.FinalizedHeader != nil, + } + } + return *update.score +} + +// UpdateScore allows the comparison between updates at the same period in order +// to find the best update chain that provides the strongest proof of being canonical. +// +// UpdateScores have a tightly packed binary encoding format for efficient p2p +// protocol transmission. Each UpdateScore is encoded in 3 bytes. +// When interpreted as a 24 bit little indian unsigned integer: +// - the lowest 10 bits contain the number of signers in the header signature aggregate +// - the next 13 bits contain the "sub-period index" which is he signed header's +// slot modulo params.SyncPeriodLength (which is correlated with the risk of the chain being +// re-orged before the previous period boundary in case of non-finalized updates) +// - the highest bit is set when the update is finalized (meaning that the finality +// header referenced by the signed header is in the same period as the signed +// header, making reorgs before the period boundary impossible +type UpdateScore struct { + SignerCount uint32 // number of signers in the header signature aggregate + SubPeriodIndex uint32 // signed header's slot modulo params.SyncPeriodLength + FinalizedHeader bool // update is considered finalized if has finalized header from the same period and 2/3 signatures +} + +// finalized returns true if the update has a header signed by at least 2/3 of +// the committee, referring to a finalized header that refers to the next sync +// committee. This condition is a close approximation of the actual finality +// condition that can only be verified by full beacon nodes. +func (u *UpdateScore) finalized() bool { + return u.FinalizedHeader && u.SignerCount >= params.SyncCommitteeSupermajority +} + +// BetterThan returns true if update u is considered better than w. +func (u UpdateScore) BetterThan(w UpdateScore) bool { + var ( + uFinalized = u.finalized() + wFinalized = w.finalized() + ) + if uFinalized != wFinalized { + return uFinalized + } + return u.SignerCount > w.SignerCount +} diff --git a/build/checksums.txt b/build/checksums.txt index 9b038582a8..adfa0bc34d 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -1,20 +1,25 @@ # This file contains sha256 checksums of optional build dependencies. -e447b498cde50215c4f7619e5124b0fc4e25fb5d16ea47271c47f278e7aa763a go1.20.3.src.tar.gz -c1e1161d6d859deb576e6cfabeb40e3d042ceb1c6f444f617c3c9d76269c3565 go1.20.3.darwin-amd64.tar.gz -86b0ed0f2b2df50fa8036eea875d1cf2d76cefdacf247c44639a1464b7e36b95 go1.20.3.darwin-arm64.tar.gz -340e80abd047c597fdc0f50a6cc59617f06c297d62f7fc77f4a0164e2da6f7aa go1.20.3.freebsd-386.tar.gz -2169fcd8b6c94c5fbe07c0b470ccfb6001d343f6548ad49f3d9ab78e3b5753c7 go1.20.3.freebsd-amd64.tar.gz -e12384311403f1389d14cc1c1295bfb4e0dd5ab919403b80da429f671a223507 go1.20.3.linux-386.tar.gz -979694c2c25c735755bf26f4f45e19e64e4811d661dd07b8c010f7a8e18adfca go1.20.3.linux-amd64.tar.gz -eb186529f13f901e7a2c4438a05c2cd90d74706aaa0a888469b2a4a617b6ee54 go1.20.3.linux-arm64.tar.gz -b421e90469a83671641f81b6e20df6500f033e9523e89cbe7b7223704dd1035c go1.20.3.linux-armv6l.tar.gz -943c89aa1624ea544a022b31e3d6e16a037200e436370bdd5fd67f3fa60be282 go1.20.3.linux-ppc64le.tar.gz -126cf823a5634ef2544b866db107b9d351d3ea70d9e240b0bdcfb46f4dcae54b go1.20.3.linux-s390x.tar.gz -37e9146e1f9d681cfcaa6fee6c7b890c44c64bc50228c9588f3c4231346d33bd go1.20.3.windows-386.zip -143a2837821c7dbacf7744cbb1a8421c1f48307c6fdfaeffc5f8c2f69e1b7932 go1.20.3.windows-amd64.zip -158cb159e00bc979f473e0f5b5a561613129c5e51067967b72b8e072e5a4db81 go1.20.3.windows-arm64.zip +# https://github.com/ethereum/execution-spec-tests/releases +24bac679f3a2d8240d8e08e7f6a70b70c2dabf673317d924cf1d1887b9fe1f81 fixtures.tar.gz +# https://go.dev/dl/ +818d46ede85682dd551ad378ef37a4d247006f12ec59b5b755601d2ce114369a go1.21.0.src.tar.gz +b314de9f704ab122c077d2ec8e67e3670affe8865479d1f01991e7ac55d65e70 go1.21.0.darwin-amd64.tar.gz +3aca44de55c5e098de2f406e98aba328898b05d509a2e2a356416faacf2c4566 go1.21.0.darwin-arm64.tar.gz +312a0065714a50862af714e7a5b3fbbd70fe68f905ffb9bcc56d42eadf6bffab go1.21.0.freebsd-386.tar.gz +b8eaa36654625df799654f77f4af0ea7bd9e5e760ebe86e68fe7c484748ae995 go1.21.0.freebsd-amd64.tar.gz +0e6f378d9b072fab0a3d9ff4d5e990d98487d47252dba8160015a61e6bd0bcba go1.21.0.linux-386.tar.gz +d0398903a16ba2232b389fb31032ddf57cac34efda306a0eebac34f0965a0742 go1.21.0.linux-amd64.tar.gz +f3d4548edf9b22f26bbd49720350bbfe59d75b7090a1a2bff1afad8214febaf3 go1.21.0.linux-arm64.tar.gz +e377a0004957c8c560a3ff99601bce612330a3d95ba3b0a2ae144165fc87deb1 go1.21.0.linux-armv6l.tar.gz +e938ffc81d8ebe5efc179240960ba22da6a841ff05d5cab7ce2547112b14a47f go1.21.0.linux-ppc64le.tar.gz +be7338df8e5d5472dfa307b0df2b446d85d001b0a2a3cdb1a14048d751b70481 go1.21.0.linux-s390x.tar.gz +af920fbb74fc3d173118dc3cc35f02a709c1de642700e92a91a7d16981df3fec go1.21.0.windows-386.zip +732121e64e0ecb07c77fdf6cc1bc5ce7b242c2d40d4ac29021ad4c64a08731f6 go1.21.0.windows-amd64.zip +41342f5a0f8c083b14c68bde738ddcd313a4f53a5854bfdfab47f0e88247de12 go1.21.0.windows-arm64.zip + +# https://github.com/golangci/golangci-lint/releases fba08acc4027f69f07cef48fbff70b8a7ecdfaa1c2aba9ad3fb31d60d9f5d4bc golangci-lint-1.51.1-darwin-amd64.tar.gz 75b8f0ff3a4e68147156be4161a49d4576f1be37a0b506473f8c482140c1e7f2 golangci-lint-1.51.1-darwin-arm64.tar.gz e06b3459aaed356e1667580be00b05f41f3b2e29685d12cdee571c23e1edb414 golangci-lint-1.51.1-freebsd-386.tar.gz diff --git a/build/ci.go b/build/ci.go index 7933724d74..6f77e5df60 100644 --- a/build/ci.go +++ b/build/ci.go @@ -120,15 +120,15 @@ var ( // 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 + // wily, yakkety, zesty, artful, cosmic, disco, eoan, groovy, hirsuite, impish, + // kinetic debDistroGoBoots = map[string]string{ - "trusty": "golang-1.11", // EOL: 04/2024 - "xenial": "golang-go", // EOL: 04/2026 - "bionic": "golang-go", // EOL: 04/2028 - "focal": "golang-go", // EOL: 04/2030 - "jammy": "golang-go", // EOL: 04/2032 - "kinetic": "golang-go", // EOL: 07/2023 - "lunar": "golang-go", // EOL: 01/2024 + "trusty": "golang-1.11", // EOL: 04/2024 + "xenial": "golang-go", // EOL: 04/2026 + "bionic": "golang-go", // EOL: 04/2028 + "focal": "golang-go", // EOL: 04/2030 + "jammy": "golang-go", // EOL: 04/2032 + "lunar": "golang-go", // EOL: 01/2024 } debGoBootPaths = map[string]string{ @@ -139,7 +139,7 @@ var ( // This is the version of Go that will be downloaded by // // go run ci.go install -dlgo - dlgoVersion = "1.20.3" + dlgoVersion = "1.21.0" // This is the version of Go that will be used to bootstrap the PPA builder. // @@ -148,6 +148,13 @@ var ( // we need to switch over to a recursive builder to jumpt across supported // versions. gobootVersion = "1.19.6" + + // This is the version of execution-spec-tests that we are using. + // When updating, you must also update build/checksums.txt. + executionSpecTestsVersion = "1.0.2" + + // This is where the tests should be unpacked. + executionSpecTestsDir = "tests/spec-tests" ) var GOBIN, _ = filepath.Abs(filepath.Join("build", "bin")) @@ -200,6 +207,7 @@ func doInstall(cmdline []string) { staticlink = flag.Bool("static", false, "Create statically-linked executable") ) flag.CommandLine.Parse(cmdline) + env := build.Env() // Configure the toolchain. tc := build.GoToolchain{GOARCH: *arch, CC: *cc} @@ -207,12 +215,16 @@ func doInstall(cmdline []string) { csdb := build.MustLoadChecksums("build/checksums.txt") tc.Root = build.DownloadGo(csdb, dlgoVersion) } - // Disable CLI markdown doc generation in release builds and enable linking - // the CKZG library since we can make it portable here. - buildTags := []string{"urfave_cli_no_docs", "ckzg"} + + // Disable CLI markdown doc generation in release builds. + buildTags := []string{"urfave_cli_no_docs"} + + // Enable linking the CKZG library since we can make it work with additional flags. + if env.UbuntuVersion != "trusty" { + buildTags = append(buildTags, "ckzg") + } // Configure the build. - env := build.Env() gobuild := tc.Go("build", buildFlags(env, *staticlink, buildTags)...) // arm64 CI builders are memory-constrained and can't handle concurrent builds, @@ -289,16 +301,26 @@ func doTest(cmdline []string) { coverage = flag.Bool("coverage", false, "Whether to record code coverage") verbose = flag.Bool("v", false, "Whether to log verbosely") race = flag.Bool("race", false, "Execute the race detector") + cachedir = flag.String("cachedir", "./build/cache", "directory for caching downloads") ) flag.CommandLine.Parse(cmdline) + // Get test fixtures. + csdb := build.MustLoadChecksums("build/checksums.txt") + downloadSpecTestFixtures(csdb, *cachedir) + // Configure the toolchain. tc := build.GoToolchain{GOARCH: *arch, CC: *cc} if *dlgo { - csdb := build.MustLoadChecksums("build/checksums.txt") tc.Root = build.DownloadGo(csdb, dlgoVersion) } - gotest := tc.Go("test", "-tags=ckzg") + gotest := tc.Go("test") + + // CI needs a bit more time for the statetests (default 10m). + gotest.Args = append(gotest.Args, "-timeout=20m") + + // Enable CKZG backend in CI. + gotest.Args = append(gotest.Args, "-tags=ckzg") // Test a single package at a time. CI builders are slow // and some tests run into timeouts under load. @@ -321,6 +343,21 @@ func doTest(cmdline []string) { build.MustRun(gotest) } +// downloadSpecTestFixtures downloads and extracts the execution-spec-tests fixtures. +func downloadSpecTestFixtures(csdb *build.ChecksumDB, cachedir string) string { + ext := ".tar.gz" + base := "fixtures" // TODO(MariusVanDerWijden) rename once the version becomes part of the filename + url := fmt.Sprintf("https://github.com/ethereum/execution-spec-tests/releases/download/v%s/%s%s", executionSpecTestsVersion, base, ext) + archivePath := filepath.Join(cachedir, base+ext) + if err := csdb.DownloadFile(url, archivePath); err != nil { + log.Fatal(err) + } + if err := build.ExtractArchive(archivePath, executionSpecTestsDir); err != nil { + log.Fatal(err) + } + return filepath.Join(cachedir, base) +} + // doLint runs golangci-lint on requested packages. func doLint(cmdline []string) { var ( diff --git a/build/deb/ethereum/deb.rules b/build/deb/ethereum/deb.rules index 475e628b2f..daca793e55 100644 --- a/build/deb/ethereum/deb.rules +++ b/build/deb/ethereum/deb.rules @@ -28,7 +28,7 @@ override_dh_auto_build: mv .mod $(GOPATH)/pkg/mod # A fresh Go was built, all dependency downloads faked, hope build works now - ../.go/bin/go run build/ci.go install -git-commit={{.Env.Commit}} -git-branch={{.Env.Branch}} -git-tag={{.Env.Tag}} -buildnum={{.Env.Buildnum}} -pull-request={{.Env.IsPullRequest}} + ../.go/bin/go run build/ci.go install -git-commit={{.Env.Commit}} -git-branch={{.Env.Branch}} -git-tag={{.Env.Tag}} -buildnum={{.Env.Buildnum}} -pull-request={{.Env.IsPullRequest}} -ubuntu {{.Distro}} override_dh_auto_test: diff --git a/build/update-license.go b/build/update-license.go index f61536470a..52a54bf66a 100644 --- a/build/update-license.go +++ b/build/update-license.go @@ -46,12 +46,13 @@ import ( "path/filepath" "regexp" "runtime" - "sort" "strconv" "strings" "sync" "text/template" "time" + + "golang.org/x/exp/slices" ) var ( @@ -152,13 +153,6 @@ func (i info) gpl() bool { return false } -// authors implements the sort.Interface for strings in case-insensitive mode. -type authors []string - -func (as authors) Len() int { return len(as) } -func (as authors) Less(i, j int) bool { return strings.ToLower(as[i]) < strings.ToLower(as[j]) } -func (as authors) Swap(i, j int) { as[i], as[j] = as[j], as[i] } - func main() { var ( files = getFiles() @@ -299,7 +293,9 @@ func writeAuthors(files []string) { } } // Write sorted list of authors back to the file. - sort.Sort(authors(list)) + slices.SortFunc(list, func(a, b string) bool { + return strings.ToLower(a) < strings.ToLower(b) + }) content := new(bytes.Buffer) content.WriteString(authorsFileHeader) for _, a := range list { diff --git a/cmd/bootnode/main.go b/cmd/bootnode/main.go index 748113aa48..5c1635de39 100644 --- a/cmd/bootnode/main.go +++ b/cmd/bootnode/main.go @@ -23,6 +23,7 @@ import ( "fmt" "net" "os" + "time" "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/crypto" @@ -107,21 +108,20 @@ func main() { if err != nil { utils.Fatalf("-ListenUDP: %v", err) } - - realaddr := conn.LocalAddr().(*net.UDPAddr) - if natm != nil { - if !realaddr.IP.IsLoopback() { - go nat.Map(natm, nil, "udp", realaddr.Port, realaddr.Port, "ethereum discovery") - } - if ext, err := natm.ExternalIP(); err == nil { - realaddr = &net.UDPAddr{IP: ext, Port: realaddr.Port} - } - } - - printNotice(&nodeKey.PublicKey, *realaddr) + defer conn.Close() db, _ := enode.OpenDB("") ln := enode.NewLocalNode(db, nodeKey) + + listenerAddr := conn.LocalAddr().(*net.UDPAddr) + if natm != nil && !listenerAddr.IP.IsLoopback() { + natAddr := doPortMapping(natm, ln, listenerAddr) + if natAddr != nil { + listenerAddr = natAddr + } + } + + printNotice(&nodeKey.PublicKey, *listenerAddr) cfg := discover.Config{ PrivateKey: nodeKey, NetRestrict: restrictList, @@ -148,3 +148,61 @@ func printNotice(nodeKey *ecdsa.PublicKey, addr net.UDPAddr) { fmt.Println("Note: you're using cmd/bootnode, a developer tool.") fmt.Println("We recommend using a regular node as bootstrap node for production deployments.") } + +func doPortMapping(natm nat.Interface, ln *enode.LocalNode, addr *net.UDPAddr) *net.UDPAddr { + const ( + protocol = "udp" + name = "ethereum discovery" + ) + newLogger := func(external int, internal int) log.Logger { + return log.New("proto", protocol, "extport", external, "intport", internal, "interface", natm) + } + + var ( + intport = addr.Port + extaddr = &net.UDPAddr{IP: addr.IP, Port: addr.Port} + mapTimeout = nat.DefaultMapTimeout + log = newLogger(addr.Port, intport) + ) + addMapping := func() { + // Get the external address. + var err error + extaddr.IP, err = natm.ExternalIP() + if err != nil { + log.Debug("Couldn't get external IP", "err", err) + return + } + // Create the mapping. + p, err := natm.AddMapping(protocol, extaddr.Port, intport, name, mapTimeout) + if err != nil { + log.Debug("Couldn't add port mapping", "err", err) + return + } + if p != uint16(extaddr.Port) { + extaddr.Port = int(p) + log = newLogger(extaddr.Port, intport) + log.Info("NAT mapped alternative port") + } else { + log.Info("NAT mapped port") + } + // Update IP/port information of the local node. + ln.SetStaticIP(extaddr.IP) + ln.SetFallbackUDP(extaddr.Port) + } + + // Perform mapping once, synchronously. + log.Info("Attempting port mapping") + addMapping() + + // Refresh the mapping periodically. + go func() { + refresh := time.NewTimer(mapTimeout) + defer refresh.Stop() + for range refresh.C { + addMapping() + refresh.Reset(mapTimeout) + } + }() + + return extaddr +} diff --git a/cmd/clef/README.md b/cmd/clef/README.md index 3891e55402..85c9c70606 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, 4=Rinkeby, 5=Goerli) (default: 1) + --chainid value Chain id to use for signing (1=mainnet, 5=Goerli) (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 2788ddc33b..a8b0bf816a 100644 --- a/cmd/clef/main.go +++ b/cmd/clef/main.go @@ -27,6 +27,7 @@ import ( "fmt" "io" "math/big" + "net" "os" "os/signal" "path/filepath" @@ -99,7 +100,7 @@ var ( chainIdFlag = &cli.Int64Flag{ Name: "chainid", Value: params.MainnetChainConfig.ChainID.Int64(), - Usage: "Chain id to use for signing (1=mainnet, 4=Rinkeby, 5=Goerli)", + Usage: "Chain id to use for signing (1=mainnet, 5=Goerli)", } rpcPortFlag = &cli.IntFlag{ Name: "http.port", @@ -326,7 +327,7 @@ func initializeSecrets(c *cli.Context) error { return err } if num != len(masterSeed) { - return fmt.Errorf("failed to read enough random") + return errors.New("failed to read enough random") } n, p := keystore.StandardScryptN, keystore.StandardScryptP if c.Bool(utils.LightKDFFlag.Name) { @@ -482,7 +483,7 @@ func initialize(c *cli.Context) error { } } else if !c.Bool(acceptFlag.Name) { if !confirm(legalWarning) { - return fmt.Errorf("aborted by user") + return errors.New("aborted by user") } fmt.Println() } @@ -590,7 +591,7 @@ func accountImport(c *cli.Context) error { Address %v Keystore file: %v -The key is now encrypted; losing the password will result in permanently losing +The key is now encrypted; losing the password will result in permanently losing access to the key and all associated funds! Make sure to backup keystore and passwords in a safe location.`, @@ -732,6 +733,7 @@ func signer(c *cli.Context) error { cors := utils.SplitAndTrim(c.String(utils.HTTPCORSDomainFlag.Name)) srv := rpc.NewServer() + srv.SetBatchLimits(node.DefaultConfig.BatchRequestLimit, node.DefaultConfig.BatchResponseMaxSize) err := node.RegisterApis(rpcAPI, []string{"account"}, srv) if err != nil { utils.Fatalf("Could not register API: %w", err) @@ -742,7 +744,7 @@ func signer(c *cli.Context) error { port := c.Int(rpcPortFlag.Name) // start http server - httpEndpoint := fmt.Sprintf("%s:%d", c.String(utils.HTTPListenAddrFlag.Name), port) + httpEndpoint := net.JoinHostPort(c.String(utils.HTTPListenAddrFlag.Name), fmt.Sprintf("%d", port)) httpServer, addr, err := node.StartHTTPEndpoint(httpEndpoint, rpc.DefaultHTTPTimeouts, handler) if err != nil { utils.Fatalf("Could not start RPC api: %v", err) @@ -844,7 +846,7 @@ func readMasterKey(ctx *cli.Context, ui core.UIClientAPI) ([]byte, error) { } masterSeed, err := decryptSeed(cipherKey, password) if err != nil { - return nil, fmt.Errorf("failed to decrypt the master seed of clef") + return nil, errors.New("failed to decrypt the master seed of clef") } if len(masterSeed) < 256 { return nil, fmt.Errorf("master seed of insufficient length, expected >255 bytes, got %d", len(masterSeed)) diff --git a/cmd/devp2p/README.md b/cmd/devp2p/README.md index 0a61304c2b..5ca7b497a2 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/crawl.go b/cmd/devp2p/crawl.go index 1b964164d8..8c0defff6d 100644 --- a/cmd/devp2p/crawl.go +++ b/cmd/devp2p/crawl.go @@ -87,11 +87,11 @@ func (c *crawler) run(timeout time.Duration, nthreads int) nodeSet { go c.runIterator(doneCh, it) } var ( - added uint64 - updated uint64 - skipped uint64 - recent uint64 - removed uint64 + added atomic.Uint64 + updated atomic.Uint64 + skipped atomic.Uint64 + recent atomic.Uint64 + removed atomic.Uint64 wg sync.WaitGroup ) wg.Add(nthreads) @@ -103,15 +103,15 @@ func (c *crawler) run(timeout time.Duration, nthreads int) nodeSet { case n := <-c.ch: switch c.updateNode(n) { case nodeSkipIncompat: - atomic.AddUint64(&skipped, 1) + skipped.Add(1) case nodeSkipRecent: - atomic.AddUint64(&recent, 1) + recent.Add(1) case nodeRemoved: - atomic.AddUint64(&removed, 1) + removed.Add(1) case nodeAdded: - atomic.AddUint64(&added, 1) + added.Add(1) default: - atomic.AddUint64(&updated, 1) + updated.Add(1) } case <-c.closed: return @@ -138,11 +138,11 @@ loop: break loop case <-statusTicker.C: log.Info("Crawling in progress", - "added", atomic.LoadUint64(&added), - "updated", atomic.LoadUint64(&updated), - "removed", atomic.LoadUint64(&removed), - "ignored(recent)", atomic.LoadUint64(&recent), - "ignored(incompatible)", atomic.LoadUint64(&skipped)) + "added", added.Load(), + "updated", updated.Load(), + "removed", removed.Load(), + "ignored(recent)", recent.Load(), + "ignored(incompatible)", skipped.Load()) } } diff --git a/cmd/devp2p/discv4cmd.go b/cmd/devp2p/discv4cmd.go index 6312263478..0117c7eb82 100644 --- a/cmd/devp2p/discv4cmd.go +++ b/cmd/devp2p/discv4cmd.go @@ -17,6 +17,7 @@ package main import ( + "errors" "fmt" "net" "strconv" @@ -177,7 +178,7 @@ func discv4Resolve(ctx *cli.Context) error { func discv4ResolveJSON(ctx *cli.Context) error { if ctx.NArg() < 1 { - return fmt.Errorf("need nodes file as argument") + return errors.New("need nodes file as argument") } nodesFile := ctx.Args().Get(0) inputSet := make(nodeSet) @@ -207,7 +208,7 @@ func discv4ResolveJSON(ctx *cli.Context) error { func discv4Crawl(ctx *cli.Context) error { if ctx.NArg() < 1 { - return fmt.Errorf("need nodes file as argument") + return errors.New("need nodes file as argument") } nodesFile := ctx.Args().First() var inputSet nodeSet @@ -336,7 +337,7 @@ func listen(ctx *cli.Context, ln *enode.LocalNode) *net.UDPConn { } func parseBootnodes(ctx *cli.Context) ([]*enode.Node, error) { - s := params.RinkebyBootnodes + s := params.MainnetBootnodes if ctx.IsSet(bootnodesFlag.Name) { input := ctx.String(bootnodesFlag.Name) if input == "" { diff --git a/cmd/devp2p/discv5cmd.go b/cmd/devp2p/discv5cmd.go index 832a4bc1f4..c5e226f0d1 100644 --- a/cmd/devp2p/discv5cmd.go +++ b/cmd/devp2p/discv5cmd.go @@ -17,6 +17,7 @@ package main import ( + "errors" "fmt" "time" @@ -98,7 +99,7 @@ func discv5Resolve(ctx *cli.Context) error { func discv5Crawl(ctx *cli.Context) error { if ctx.NArg() < 1 { - return fmt.Errorf("need nodes file as argument") + return errors.New("need nodes file as argument") } nodesFile := ctx.Args().First() var inputSet nodeSet diff --git a/cmd/devp2p/dns_cloudflare.go b/cmd/devp2p/dns_cloudflare.go index 798fdc7332..903d754dd7 100644 --- a/cmd/devp2p/dns_cloudflare.go +++ b/cmd/devp2p/dns_cloudflare.go @@ -18,6 +18,7 @@ package main import ( "context" + "errors" "fmt" "strings" @@ -48,7 +49,7 @@ type cloudflareClient struct { func newCloudflareClient(ctx *cli.Context) *cloudflareClient { token := ctx.String(cloudflareTokenFlag.Name) if token == "" { - exit(fmt.Errorf("need cloudflare API token to proceed")) + exit(errors.New("need cloudflare API token to proceed")) } api, err := cloudflare.NewWithAPIToken(token) if err != nil { diff --git a/cmd/devp2p/dns_route53.go b/cmd/devp2p/dns_route53.go index 400ab1b1cf..21a32f9414 100644 --- a/cmd/devp2p/dns_route53.go +++ b/cmd/devp2p/dns_route53.go @@ -20,7 +20,6 @@ import ( "context" "errors" "fmt" - "sort" "strconv" "strings" "time" @@ -33,6 +32,7 @@ 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 ( @@ -81,7 +81,7 @@ func newRoute53Client(ctx *cli.Context) *route53Client { akey := ctx.String(route53AccessKeyFlag.Name) asec := ctx.String(route53AccessSecretFlag.Name) if akey == "" || asec == "" { - exit(fmt.Errorf("need Route53 Access Key ID and secret to proceed")) + exit(errors.New("need Route53 Access Key ID and secret to proceed")) } creds := aws.NewCredentialsCache(credentials.NewStaticCredentialsProvider(akey, asec, "")) cfg, err := config.LoadDefaultConfig(context.Background(), config.WithCredentialsProvider(creds)) @@ -288,11 +288,17 @@ func makeDeletionChanges(records map[string]recordSet, keep map[string]string) [ // sortChanges ensures DNS changes are in leaf-added -> root-changed -> leaf-deleted order. func sortChanges(changes []types.Change) { score := map[string]int{"CREATE": 1, "UPSERT": 2, "DELETE": 3} - sort.Slice(changes, func(i, j int) bool { - if changes[i].Action == changes[j].Action { - return *changes[i].ResourceRecordSet.Name < *changes[j].ResourceRecordSet.Name + slices.SortFunc(changes, func(a, b types.Change) int { + if a.Action == b.Action { + return strings.Compare(*a.ResourceRecordSet.Name, *b.ResourceRecordSet.Name) } - return score[string(changes[i].Action)] < score[string(changes[j].Action)] + if score[string(a.Action)] < score[string(b.Action)] { + return -1 + } + if score[string(a.Action)] > score[string(b.Action)] { + return 1 + } + return 0 }) } diff --git a/cmd/devp2p/dnscmd.go b/cmd/devp2p/dnscmd.go index 58eb6e8db1..0fce7b1030 100644 --- a/cmd/devp2p/dnscmd.go +++ b/cmd/devp2p/dnscmd.go @@ -19,6 +19,7 @@ package main import ( "crypto/ecdsa" "encoding/json" + "errors" "fmt" "os" "path/filepath" @@ -147,7 +148,7 @@ func dnsSync(ctx *cli.Context) error { func dnsSign(ctx *cli.Context) error { if ctx.NArg() < 2 { - return fmt.Errorf("need tree definition directory and key file as arguments") + return errors.New("need tree definition directory and key file as arguments") } var ( defdir = ctx.Args().Get(0) @@ -201,7 +202,7 @@ func directoryName(dir string) string { // dnsToTXT performs dnsTXTCommand. func dnsToTXT(ctx *cli.Context) error { if ctx.NArg() < 1 { - return fmt.Errorf("need tree definition directory as argument") + return errors.New("need tree definition directory as argument") } output := ctx.Args().Get(1) if output == "" { @@ -218,7 +219,7 @@ func dnsToTXT(ctx *cli.Context) error { // dnsToCloudflare performs dnsCloudflareCommand. func dnsToCloudflare(ctx *cli.Context) error { if ctx.NArg() != 1 { - return fmt.Errorf("need tree definition directory as argument") + return errors.New("need tree definition directory as argument") } domain, t, err := loadTreeDefinitionForExport(ctx.Args().Get(0)) if err != nil { @@ -231,7 +232,7 @@ func dnsToCloudflare(ctx *cli.Context) error { // dnsToRoute53 performs dnsRoute53Command. func dnsToRoute53(ctx *cli.Context) error { if ctx.NArg() != 1 { - return fmt.Errorf("need tree definition directory as argument") + return errors.New("need tree definition directory as argument") } domain, t, err := loadTreeDefinitionForExport(ctx.Args().Get(0)) if err != nil { @@ -244,7 +245,7 @@ func dnsToRoute53(ctx *cli.Context) error { // dnsNukeRoute53 performs dnsRoute53NukeCommand. func dnsNukeRoute53(ctx *cli.Context) error { if ctx.NArg() != 1 { - return fmt.Errorf("need domain name as argument") + return errors.New("need domain name as argument") } client := newRoute53Client(ctx) return client.deleteDomain(ctx.Args().First()) @@ -363,10 +364,10 @@ func loadTreeDefinitionForExport(dir string) (domain string, t *dnsdisc.Tree, er // tree's signature if valid. func ensureValidTreeSignature(t *dnsdisc.Tree, pubkey *ecdsa.PublicKey, sig string) error { if sig == "" { - return fmt.Errorf("missing signature, run 'devp2p dns sign' first") + return errors.New("missing signature, run 'devp2p dns sign' first") } if err := t.SetSignature(pubkey, sig); err != nil { - return fmt.Errorf("invalid signature on tree, run 'devp2p dns sign' to update it") + return errors.New("invalid signature on tree, run 'devp2p dns sign' to update it") } return nil } diff --git a/cmd/devp2p/enrcmd.go b/cmd/devp2p/enrcmd.go index 2110437103..c5a97c8411 100644 --- a/cmd/devp2p/enrcmd.go +++ b/cmd/devp2p/enrcmd.go @@ -20,6 +20,7 @@ import ( "bytes" "encoding/base64" "encoding/hex" + "errors" "fmt" "io" "net" @@ -48,7 +49,7 @@ func enrdump(ctx *cli.Context) error { var source string if file := ctx.String(fileFlag.Name); file != "" { if ctx.NArg() != 0 { - return fmt.Errorf("can't dump record from command-line argument in -file mode") + return errors.New("can't dump record from command-line argument in -file mode") } var b []byte var err error @@ -64,7 +65,7 @@ func enrdump(ctx *cli.Context) error { } else if ctx.NArg() == 1 { source = ctx.Args().First() } else { - return fmt.Errorf("need record as argument") + return errors.New("need record as argument") } r, err := parseRecord(source) diff --git a/cmd/devp2p/internal/ethtest/chain.go b/cmd/devp2p/internal/ethtest/chain.go index f4db05db8e..938159ec52 100644 --- a/cmd/devp2p/internal/ethtest/chain.go +++ b/cmd/devp2p/internal/ethtest/chain.go @@ -19,6 +19,7 @@ package ethtest import ( "compress/gzip" "encoding/json" + "errors" "fmt" "io" "math/big" @@ -76,7 +77,7 @@ func (c *Chain) RootAt(height int) common.Hash { // ForkID gets the fork id of the chain. func (c *Chain) ForkID() forkid.ID { - return forkid.NewID(c.chainConfig, c.blocks[0].Hash(), uint64(c.Len()), c.blocks[0].Time()) + return forkid.NewID(c.chainConfig, c.blocks[0], uint64(c.Len()), c.blocks[0].Time()) } // Shorten returns a copy chain of a desired height from the imported @@ -98,7 +99,7 @@ func (c *Chain) Head() *types.Block { func (c *Chain) GetHeaders(req *GetBlockHeaders) ([]*types.Header, error) { if req.Amount < 1 { - return nil, fmt.Errorf("no block headers requested") + return nil, errors.New("no block headers requested") } headers := make([]*types.Header, req.Amount) diff --git a/cmd/devp2p/internal/ethtest/helpers.go b/cmd/devp2p/internal/ethtest/helpers.go index 70ed2d2106..bc901bdeb0 100644 --- a/cmd/devp2p/internal/ethtest/helpers.go +++ b/cmd/devp2p/internal/ethtest/helpers.go @@ -17,6 +17,7 @@ package ethtest import ( + "errors" "fmt" "net" "reflect" @@ -185,7 +186,7 @@ loop: } // make sure eth protocol version is set for negotiation if c.negotiatedProtoVersion == 0 { - return nil, fmt.Errorf("eth protocol version must be set in Conn") + return nil, errors.New("eth protocol version must be set in Conn") } if status == nil { // default status message diff --git a/cmd/devp2p/internal/ethtest/suite_test.go b/cmd/devp2p/internal/ethtest/suite_test.go index 8a2b132fa3..c5bcc3db1d 100644 --- a/cmd/devp2p/internal/ethtest/suite_test.go +++ b/cmd/devp2p/internal/ethtest/suite_test.go @@ -109,15 +109,13 @@ func setupGeth(stack *node.Node) error { } backend, err := eth.New(stack, ðconfig.Config{ - Genesis: &chain.genesis, - NetworkId: chain.genesis.Config.ChainID.Uint64(), // 19763 - DatabaseCache: 10, - TrieCleanCache: 10, - TrieCleanCacheJournal: "", - TrieCleanCacheRejournal: 60 * time.Minute, - TrieDirtyCache: 16, - TrieTimeout: 60 * time.Minute, - SnapshotCache: 10, + Genesis: &chain.genesis, + NetworkId: chain.genesis.Config.ChainID.Uint64(), // 19763 + DatabaseCache: 10, + TrieCleanCache: 10, + TrieDirtyCache: 16, + TrieTimeout: 60 * time.Minute, + SnapshotCache: 10, }) if err != nil { return err diff --git a/cmd/devp2p/internal/ethtest/transaction.go b/cmd/devp2p/internal/ethtest/transaction.go index bf3a4b7f06..db5199d334 100644 --- a/cmd/devp2p/internal/ethtest/transaction.go +++ b/cmd/devp2p/internal/ethtest/transaction.go @@ -17,6 +17,7 @@ package ethtest import ( + "errors" "fmt" "math/big" "strings" @@ -39,7 +40,7 @@ func (s *Suite) sendSuccessfulTxs(t *utesting.T) error { } for i, tx := range tests { if tx == nil { - return fmt.Errorf("could not find tx to send") + return errors.New("could not find tx to send") } t.Logf("Testing tx propagation %d: sending tx %v %v %v\n", i, tx.Hash().String(), tx.GasPrice(), tx.Gas()) // get previous tx if exists for reference in case of old tx propagation @@ -348,7 +349,7 @@ func generateTxs(s *Suite, numTxs int) (map[common.Hash]common.Hash, []*types.Tr nextTx := getNextTxFromChain(s) if nextTx == nil { - return nil, nil, fmt.Errorf("failed to get the next transaction") + return nil, nil, errors.New("failed to get the next transaction") } gas := nextTx.Gas() @@ -357,7 +358,7 @@ func generateTxs(s *Suite, numTxs int) (map[common.Hash]common.Hash, []*types.Tr for i := 0; i < numTxs; i++ { tx := generateTx(s.chain.chainConfig, nonce, gas) if tx == nil { - return nil, nil, fmt.Errorf("failed to get the next transaction") + return nil, nil, errors.New("failed to get the next transaction") } txHashMap[tx.Hash()] = tx.Hash() txs[i] = tx diff --git a/cmd/devp2p/internal/ethtest/types.go b/cmd/devp2p/internal/ethtest/types.go index 3c7b6dbcf1..afa9a9c8c6 100644 --- a/cmd/devp2p/internal/ethtest/types.go +++ b/cmd/devp2p/internal/ethtest/types.go @@ -18,6 +18,7 @@ package ethtest import ( "crypto/ecdsa" + "errors" "fmt" "time" @@ -286,5 +287,5 @@ func (c *Conn) ReadSnap(id uint64) (Message, error) { } return snpMsg.(Message), nil } - return nil, fmt.Errorf("request timed out") + return nil, errors.New("request timed out") } diff --git a/cmd/devp2p/internal/v4test/discv4tests.go b/cmd/devp2p/internal/v4test/discv4tests.go index d799e4194b..3afcfd0698 100644 --- a/cmd/devp2p/internal/v4test/discv4tests.go +++ b/cmd/devp2p/internal/v4test/discv4tests.go @@ -19,6 +19,7 @@ package v4test import ( "bytes" "crypto/rand" + "errors" "fmt" "net" "time" @@ -119,7 +120,7 @@ func (te *testenv) checkPingPong(pingHash []byte) error { // and a PING. The two packets do not have to be in any particular order. func (te *testenv) checkPong(reply v4wire.Packet, pingHash []byte) error { if reply == nil { - return fmt.Errorf("expected PONG reply, got nil") + return errors.New("expected PONG reply, got nil") } if reply.Kind() != v4wire.PongPacket { return fmt.Errorf("expected PONG reply, got %v %v", reply.Name(), reply) diff --git a/cmd/devp2p/keycmd.go b/cmd/devp2p/keycmd.go index f409057fe0..98d7bd76ae 100644 --- a/cmd/devp2p/keycmd.go +++ b/cmd/devp2p/keycmd.go @@ -17,6 +17,7 @@ package main import ( + "errors" "fmt" "net" @@ -86,7 +87,7 @@ var ( func genkey(ctx *cli.Context) error { if ctx.NArg() != 1 { - return fmt.Errorf("need key file as argument") + return errors.New("need key file as argument") } file := ctx.Args().Get(0) @@ -126,7 +127,7 @@ func keyToRecord(ctx *cli.Context) error { func makeRecord(ctx *cli.Context) (*enode.Node, error) { if ctx.NArg() != 1 { - return nil, fmt.Errorf("need key file as argument") + return nil, errors.New("need key file as argument") } var ( diff --git a/cmd/devp2p/nodeset.go b/cmd/devp2p/nodeset.go index 33c39f4b9e..7360dc5bcf 100644 --- a/cmd/devp2p/nodeset.go +++ b/cmd/devp2p/nodeset.go @@ -21,11 +21,11 @@ import ( "encoding/json" "fmt" "os" - "sort" "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/p2p/enode" + "golang.org/x/exp/slices" ) const jsonIndent = " " @@ -77,8 +77,8 @@ func (ns nodeSet) nodes() []*enode.Node { result = append(result, n.N) } // Sort by ID. - sort.Slice(result, func(i, j int) bool { - return bytes.Compare(result[i].ID().Bytes(), result[j].ID().Bytes()) < 0 + slices.SortFunc(result, func(a, b *enode.Node) int { + return bytes.Compare(a.ID().Bytes(), b.ID().Bytes()) }) return result } @@ -103,8 +103,14 @@ func (ns nodeSet) topN(n int) nodeSet { for _, v := range ns { byscore = append(byscore, v) } - sort.Slice(byscore, func(i, j int) bool { - return byscore[i].Score >= byscore[j].Score + slices.SortFunc(byscore, func(a, b nodeJSON) int { + if a.Score > b.Score { + return -1 + } + if a.Score < b.Score { + return 1 + } + return 0 }) result := make(nodeSet, n) for _, v := range byscore[:n] { diff --git a/cmd/devp2p/nodesetcmd.go b/cmd/devp2p/nodesetcmd.go index 2faa2882e5..6fbc185ad8 100644 --- a/cmd/devp2p/nodesetcmd.go +++ b/cmd/devp2p/nodesetcmd.go @@ -25,6 +25,7 @@ import ( "strings" "time" + "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/forkid" "github.com/ethereum/go-ethereum/p2p/enr" "github.com/ethereum/go-ethereum/params" @@ -59,7 +60,7 @@ var ( func nodesetInfo(ctx *cli.Context) error { if ctx.NArg() < 1 { - return fmt.Errorf("need nodes file as argument") + return errors.New("need nodes file as argument") } ns := loadNodesJSON(ctx.Args().First()) @@ -98,7 +99,7 @@ func showAttributeCounts(ns nodeSet) { func nodesetFilter(ctx *cli.Context) error { if ctx.NArg() < 1 { - return fmt.Errorf("need nodes file as argument") + return errors.New("need nodes file as argument") } // Parse -limit. limit, err := parseFilterLimit(ctx.Args().Tail()) @@ -228,13 +229,13 @@ func ethFilter(args []string) (nodeFilter, error) { var filter forkid.Filter switch args[0] { case "mainnet": - filter = forkid.NewStaticFilter(params.MainnetChainConfig, params.MainnetGenesisHash) - case "rinkeby": - filter = forkid.NewStaticFilter(params.RinkebyChainConfig, params.RinkebyGenesisHash) + filter = forkid.NewStaticFilter(params.MainnetChainConfig, core.DefaultGenesisBlock().ToBlock()) case "goerli": - filter = forkid.NewStaticFilter(params.GoerliChainConfig, params.GoerliGenesisHash) + filter = forkid.NewStaticFilter(params.GoerliChainConfig, core.DefaultGoerliGenesisBlock().ToBlock()) case "sepolia": - filter = forkid.NewStaticFilter(params.SepoliaChainConfig, params.SepoliaGenesisHash) + filter = forkid.NewStaticFilter(params.SepoliaChainConfig, core.DefaultSepoliaGenesisBlock().ToBlock()) + case "holesky": + filter = forkid.NewStaticFilter(params.HoleskyChainConfig, core.DefaultHoleskyGenesisBlock().ToBlock()) default: return nil, fmt.Errorf("unknown network %q", args[0]) } diff --git a/cmd/devp2p/rlpxcmd.go b/cmd/devp2p/rlpxcmd.go index 42b38120c4..dccecf3c37 100644 --- a/cmd/devp2p/rlpxcmd.go +++ b/cmd/devp2p/rlpxcmd.go @@ -17,6 +17,7 @@ package main import ( + "errors" "fmt" "net" @@ -91,7 +92,7 @@ func rlpxPing(ctx *cli.Context) error { case 1: var msg []p2p.DiscReason if rlp.DecodeBytes(data, &msg); len(msg) == 0 { - return fmt.Errorf("invalid disconnect message") + return errors.New("invalid disconnect message") } return fmt.Errorf("received disconnect message: %v", msg[0]) default: diff --git a/cmd/evm/README.md b/cmd/evm/README.md index 2962158612..e6c6fe06ad 100644 --- a/cmd/evm/README.md +++ b/cmd/evm/README.md @@ -342,7 +342,7 @@ To make `t8n` apply these, the following inputs are required: - For ethash, it is `5000000000000000000` `wei`, - If this is not defined, mining rewards are not applied, - A value of `0` is valid, and causes accounts to be 'touched'. -- For each ommer, the tool needs to be given an `addres\` and a `delta`. This +- For each ommer, the tool needs to be given an `address\` and a `delta`. This is done via the `ommers` field in `env`. Note: the tool does not verify that e.g. the normal uncle rules apply, diff --git a/cmd/evm/blockrunner.go b/cmd/evm/blockrunner.go index ffd76b8fb0..0be5f69711 100644 --- a/cmd/evm/blockrunner.go +++ b/cmd/evm/blockrunner.go @@ -22,6 +22,9 @@ import ( "fmt" "os" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/eth/tracers/logger" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/tests" "github.com/urfave/cli/v2" @@ -42,7 +45,16 @@ func blockTestCmd(ctx *cli.Context) error { glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false))) glogger.Verbosity(log.Lvl(ctx.Int(VerbosityFlag.Name))) log.Root().SetHandler(glogger) - + var tracer vm.EVMLogger + // Configure the EVM logger + if ctx.Bool(MachineFlag.Name) { + tracer = logger.NewJSONLogger(&logger.Config{ + EnableMemory: !ctx.Bool(DisableMemoryFlag.Name), + DisableStack: ctx.Bool(DisableStackFlag.Name), + DisableStorage: ctx.Bool(DisableStorageFlag.Name), + EnableReturnData: !ctx.Bool(DisableReturnDataFlag.Name), + }, os.Stderr) + } // Load the test content from the input file src, err := os.ReadFile(ctx.Args().First()) if err != nil { @@ -53,7 +65,7 @@ func blockTestCmd(ctx *cli.Context) error { return err } for i, test := range tests { - if err := test.Run(false); err != nil { + if err := test.Run(false, rawdb.HashScheme, tracer); err != nil { return fmt.Errorf("test %v: %w", i, err) } } diff --git a/cmd/evm/internal/t8ntool/block.go b/cmd/evm/internal/t8ntool/block.go index ac3031d6ef..09dca8984e 100644 --- a/cmd/evm/internal/t8ntool/block.go +++ b/cmd/evm/internal/t8ntool/block.go @@ -171,18 +171,18 @@ func (i *bbInput) sealClique(block *types.Block) (*types.Block, error) { // If any clique value overwrites an explicit header value, fail // to avoid silently building a block with unexpected values. if i.Header.Extra != nil { - return nil, NewError(ErrorConfig, fmt.Errorf("sealing with clique will overwrite provided extra data")) + return nil, NewError(ErrorConfig, errors.New("sealing with clique will overwrite provided extra data")) } header := block.Header() if i.Clique.Voted != nil { if i.Header.Coinbase != nil { - return nil, NewError(ErrorConfig, fmt.Errorf("sealing with clique and voting will overwrite provided coinbase")) + return nil, NewError(ErrorConfig, errors.New("sealing with clique and voting will overwrite provided coinbase")) } header.Coinbase = *i.Clique.Voted } if i.Clique.Authorize != nil { if i.Header.Nonce != nil { - return nil, NewError(ErrorConfig, fmt.Errorf("sealing with clique and voting will overwrite provided nonce")) + return nil, NewError(ErrorConfig, errors.New("sealing with clique and voting will overwrite provided nonce")) } if *i.Clique.Authorize { header.Nonce = [8]byte{} @@ -306,7 +306,7 @@ func readInput(ctx *cli.Context) (*bbInput, error) { return inputData, nil } -// dispatchOutput writes the output data to either stderr or stdout, or to the specified +// dispatchBlock writes the output data to either stderr or stdout, or to the specified // files func dispatchBlock(ctx *cli.Context, baseDir string, block *types.Block) error { raw, _ := rlp.EncodeToBytes(block) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 5633198d39..bb14ac63ca 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -19,12 +19,12 @@ package t8ntool import ( "fmt" "math/big" - "os" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/consensus/misc" + "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" @@ -47,17 +47,19 @@ type Prestate struct { // ExecutionResult contains the execution status after running a state test, any // error that might have occurred and a dump of the final state if requested. type ExecutionResult struct { - StateRoot common.Hash `json:"stateRoot"` - TxRoot common.Hash `json:"txRoot"` - ReceiptRoot common.Hash `json:"receiptsRoot"` - LogsHash common.Hash `json:"logsHash"` - Bloom types.Bloom `json:"logsBloom" gencodec:"required"` - Receipts types.Receipts `json:"receipts"` - Rejected []*rejectedTx `json:"rejected,omitempty"` - Difficulty *math.HexOrDecimal256 `json:"currentDifficulty" gencodec:"required"` - GasUsed math.HexOrDecimal64 `json:"gasUsed"` - BaseFee *math.HexOrDecimal256 `json:"currentBaseFee,omitempty"` - WithdrawalsRoot *common.Hash `json:"withdrawalsRoot,omitempty"` + StateRoot common.Hash `json:"stateRoot"` + TxRoot common.Hash `json:"txRoot"` + ReceiptRoot common.Hash `json:"receiptsRoot"` + LogsHash common.Hash `json:"logsHash"` + Bloom types.Bloom `json:"logsBloom" gencodec:"required"` + Receipts types.Receipts `json:"receipts"` + Rejected []*rejectedTx `json:"rejected,omitempty"` + Difficulty *math.HexOrDecimal256 `json:"currentDifficulty" gencodec:"required"` + GasUsed math.HexOrDecimal64 `json:"gasUsed"` + BaseFee *math.HexOrDecimal256 `json:"currentBaseFee,omitempty"` + WithdrawalsRoot *common.Hash `json:"withdrawalsRoot,omitempty"` + CurrentExcessBlobGas *math.HexOrDecimal64 `json:"currentExcessBlobGas,omitempty"` + CurrentBlobGasUsed *math.HexOrDecimal64 `json:"currentBlobGasUsed,omitempty"` } type ommer struct { @@ -67,37 +69,44 @@ type ommer struct { //go:generate go run github.com/fjl/gencodec -type stEnv -field-override stEnvMarshaling -out gen_stenv.go type stEnv struct { - Coinbase common.Address `json:"currentCoinbase" gencodec:"required"` - Difficulty *big.Int `json:"currentDifficulty"` - Random *big.Int `json:"currentRandom"` - ParentDifficulty *big.Int `json:"parentDifficulty"` - ParentBaseFee *big.Int `json:"parentBaseFee,omitempty"` - ParentGasUsed uint64 `json:"parentGasUsed,omitempty"` - ParentGasLimit uint64 `json:"parentGasLimit,omitempty"` - GasLimit uint64 `json:"currentGasLimit" gencodec:"required"` - Number uint64 `json:"currentNumber" gencodec:"required"` - Timestamp uint64 `json:"currentTimestamp" gencodec:"required"` - ParentTimestamp uint64 `json:"parentTimestamp,omitempty"` - BlockHashes map[math.HexOrDecimal64]common.Hash `json:"blockHashes,omitempty"` - Ommers []ommer `json:"ommers,omitempty"` - Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"` - BaseFee *big.Int `json:"currentBaseFee,omitempty"` - ParentUncleHash common.Hash `json:"parentUncleHash"` + Coinbase common.Address `json:"currentCoinbase" gencodec:"required"` + Difficulty *big.Int `json:"currentDifficulty"` + Random *big.Int `json:"currentRandom"` + ParentDifficulty *big.Int `json:"parentDifficulty"` + ParentBaseFee *big.Int `json:"parentBaseFee,omitempty"` + ParentGasUsed uint64 `json:"parentGasUsed,omitempty"` + ParentGasLimit uint64 `json:"parentGasLimit,omitempty"` + GasLimit uint64 `json:"currentGasLimit" gencodec:"required"` + Number uint64 `json:"currentNumber" gencodec:"required"` + Timestamp uint64 `json:"currentTimestamp" gencodec:"required"` + ParentTimestamp uint64 `json:"parentTimestamp,omitempty"` + BlockHashes map[math.HexOrDecimal64]common.Hash `json:"blockHashes,omitempty"` + Ommers []ommer `json:"ommers,omitempty"` + Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"` + BaseFee *big.Int `json:"currentBaseFee,omitempty"` + ParentUncleHash common.Hash `json:"parentUncleHash"` + ExcessBlobGas *uint64 `json:"excessBlobGas,omitempty"` + ParentExcessBlobGas *uint64 `json:"parentExcessBlobGas,omitempty"` + ParentBlobGasUsed *uint64 `json:"parentBlobGasUsed,omitempty"` + ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot"` } type stEnvMarshaling struct { - Coinbase common.UnprefixedAddress - Difficulty *math.HexOrDecimal256 - Random *math.HexOrDecimal256 - ParentDifficulty *math.HexOrDecimal256 - ParentBaseFee *math.HexOrDecimal256 - ParentGasUsed math.HexOrDecimal64 - ParentGasLimit math.HexOrDecimal64 - GasLimit math.HexOrDecimal64 - Number math.HexOrDecimal64 - Timestamp math.HexOrDecimal64 - ParentTimestamp math.HexOrDecimal64 - BaseFee *math.HexOrDecimal256 + Coinbase common.UnprefixedAddress + Difficulty *math.HexOrDecimal256 + Random *math.HexOrDecimal256 + ParentDifficulty *math.HexOrDecimal256 + ParentBaseFee *math.HexOrDecimal256 + ParentGasUsed math.HexOrDecimal64 + ParentGasLimit math.HexOrDecimal64 + GasLimit math.HexOrDecimal64 + Number math.HexOrDecimal64 + Timestamp math.HexOrDecimal64 + ParentTimestamp math.HexOrDecimal64 + BaseFee *math.HexOrDecimal256 + ExcessBlobGas *math.HexOrDecimal64 + ParentExcessBlobGas *math.HexOrDecimal64 + ParentBlobGasUsed *math.HexOrDecimal64 } type rejectedTx struct { @@ -154,6 +163,19 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, rnd := common.BigToHash(pre.Env.Random) vmContext.Random = &rnd } + // If excessBlobGas is defined, add it to the vmContext. + if pre.Env.ExcessBlobGas != nil { + vmContext.ExcessBlobGas = pre.Env.ExcessBlobGas + } else { + // If it is not explicitly defined, but we have the parent values, we try + // to calculate it ourselves. + parentExcessBlobGas := pre.Env.ParentExcessBlobGas + parentBlobGasUsed := pre.Env.ParentBlobGasUsed + if parentExcessBlobGas != nil && parentBlobGasUsed != nil { + excessBlobGas := eip4844.CalcExcessBlobGas(*parentExcessBlobGas, *parentBlobGasUsed) + vmContext.ExcessBlobGas = &excessBlobGas + } + } // If DAO is supported/enabled, we need to handle it here. In geth 'proper', it's // done in StateProcessor.Process(block, ...), right before transactions are applied. if chainConfig.DAOForkSupport && @@ -161,8 +183,18 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, chainConfig.DAOForkBlock.Cmp(new(big.Int).SetUint64(pre.Env.Number)) == 0 { misc.ApplyDAOHardFork(statedb) } - + if beaconRoot := pre.Env.ParentBeaconBlockRoot; beaconRoot != nil { + evm := vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vmConfig) + core.ProcessBeaconBlockRoot(*beaconRoot, evm, statedb) + } + var blobGasUsed uint64 for i, tx := range txs { + if tx.Type() == types.BlobTxType && vmContext.ExcessBlobGas == nil { + errMsg := "blob tx used but field env.ExcessBlobGas missing" + log.Warn("rejected tx", "index", i, "hash", tx.Hash(), "error", errMsg) + rejectedTxs = append(rejectedTxs, &rejectedTx{i, errMsg}) + continue + } msg, err := core.TransactionToMessage(tx, signer, pre.Env.BaseFee) if err != nil { log.Warn("rejected tx", "index", i, "hash", tx.Hash(), "error", err) @@ -192,6 +224,9 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, gaspool.SetGas(prevGas) continue } + if tx.Type() == types.BlobTxType { + blobGasUsed += params.BlobTxBlobGasPerBlob + } includedTxs = append(includedTxs, tx) if hashError != nil { return nil, nil, NewError(ErrorMissingBlockhash, hashError) @@ -240,7 +275,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, if miningReward >= 0 { // Add mining reward. The mining reward may be `0`, which only makes a difference in the cases // where - // - the coinbase suicided, or + // - 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 var ( @@ -267,9 +302,8 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, statedb.AddBalance(w.Address, amount) } // Commit block - root, err := statedb.Commit(chainConfig.IsEIP158(vmContext.BlockNumber)) + root, err := statedb.Commit(vmContext.BlockNumber.Uint64(), chainConfig.IsEIP158(vmContext.BlockNumber)) if err != nil { - fmt.Fprintf(os.Stderr, "Could not commit state: %v", err) return nil, nil, NewError(ErrorEVM, fmt.Errorf("could not commit state: %v", err)) } execRs := &ExecutionResult{ @@ -288,6 +322,16 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, h := types.DeriveSha(types.Withdrawals(pre.Env.Withdrawals), trie.NewStackTrie(nil)) execRs.WithdrawalsRoot = &h } + if vmContext.ExcessBlobGas != nil { + execRs.CurrentExcessBlobGas = (*math.HexOrDecimal64)(vmContext.ExcessBlobGas) + execRs.CurrentBlobGasUsed = (*math.HexOrDecimal64)(&blobGasUsed) + } + // Re-create statedb instance with new root upon the updated database + // for accessing latest states. + statedb, err = state.New(root, statedb.Database(), nil) + if err != nil { + return nil, nil, NewError(ErrorEVM, fmt.Errorf("could not reopen state: %v", err)) + } return statedb, execRs, nil } @@ -303,7 +347,7 @@ func MakePreState(db ethdb.Database, accounts core.GenesisAlloc) *state.StateDB } } // Commit and re-open to start with a clean state. - root, _ := statedb.Commit(false) + root, _ := statedb.Commit(0, false) statedb, _ = state.New(root, sdb, nil) return statedb } diff --git a/cmd/evm/internal/t8ntool/gen_stenv.go b/cmd/evm/internal/t8ntool/gen_stenv.go index c2cc3a2c8a..bb195ef64b 100644 --- a/cmd/evm/internal/t8ntool/gen_stenv.go +++ b/cmd/evm/internal/t8ntool/gen_stenv.go @@ -17,22 +17,26 @@ var _ = (*stEnvMarshaling)(nil) // MarshalJSON marshals as JSON. func (s stEnv) MarshalJSON() ([]byte, error) { type stEnv struct { - Coinbase common.UnprefixedAddress `json:"currentCoinbase" gencodec:"required"` - Difficulty *math.HexOrDecimal256 `json:"currentDifficulty"` - Random *math.HexOrDecimal256 `json:"currentRandom"` - ParentDifficulty *math.HexOrDecimal256 `json:"parentDifficulty"` - ParentBaseFee *math.HexOrDecimal256 `json:"parentBaseFee,omitempty"` - ParentGasUsed math.HexOrDecimal64 `json:"parentGasUsed,omitempty"` - ParentGasLimit math.HexOrDecimal64 `json:"parentGasLimit,omitempty"` - GasLimit math.HexOrDecimal64 `json:"currentGasLimit" gencodec:"required"` - Number math.HexOrDecimal64 `json:"currentNumber" gencodec:"required"` - Timestamp math.HexOrDecimal64 `json:"currentTimestamp" gencodec:"required"` - ParentTimestamp math.HexOrDecimal64 `json:"parentTimestamp,omitempty"` - BlockHashes map[math.HexOrDecimal64]common.Hash `json:"blockHashes,omitempty"` - Ommers []ommer `json:"ommers,omitempty"` - Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"` - BaseFee *math.HexOrDecimal256 `json:"currentBaseFee,omitempty"` - ParentUncleHash common.Hash `json:"parentUncleHash"` + Coinbase common.UnprefixedAddress `json:"currentCoinbase" gencodec:"required"` + Difficulty *math.HexOrDecimal256 `json:"currentDifficulty"` + Random *math.HexOrDecimal256 `json:"currentRandom"` + ParentDifficulty *math.HexOrDecimal256 `json:"parentDifficulty"` + ParentBaseFee *math.HexOrDecimal256 `json:"parentBaseFee,omitempty"` + ParentGasUsed math.HexOrDecimal64 `json:"parentGasUsed,omitempty"` + ParentGasLimit math.HexOrDecimal64 `json:"parentGasLimit,omitempty"` + GasLimit math.HexOrDecimal64 `json:"currentGasLimit" gencodec:"required"` + Number math.HexOrDecimal64 `json:"currentNumber" gencodec:"required"` + Timestamp math.HexOrDecimal64 `json:"currentTimestamp" gencodec:"required"` + ParentTimestamp math.HexOrDecimal64 `json:"parentTimestamp,omitempty"` + BlockHashes map[math.HexOrDecimal64]common.Hash `json:"blockHashes,omitempty"` + Ommers []ommer `json:"ommers,omitempty"` + Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"` + BaseFee *math.HexOrDecimal256 `json:"currentBaseFee,omitempty"` + ParentUncleHash common.Hash `json:"parentUncleHash"` + ExcessBlobGas *math.HexOrDecimal64 `json:"excessBlobGas,omitempty"` + ParentExcessBlobGas *math.HexOrDecimal64 `json:"parentExcessBlobGas,omitempty"` + ParentBlobGasUsed *math.HexOrDecimal64 `json:"parentBlobGasUsed,omitempty"` + ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot"` } var enc stEnv enc.Coinbase = common.UnprefixedAddress(s.Coinbase) @@ -51,28 +55,36 @@ func (s stEnv) MarshalJSON() ([]byte, error) { enc.Withdrawals = s.Withdrawals enc.BaseFee = (*math.HexOrDecimal256)(s.BaseFee) enc.ParentUncleHash = s.ParentUncleHash + enc.ExcessBlobGas = (*math.HexOrDecimal64)(s.ExcessBlobGas) + enc.ParentExcessBlobGas = (*math.HexOrDecimal64)(s.ParentExcessBlobGas) + enc.ParentBlobGasUsed = (*math.HexOrDecimal64)(s.ParentBlobGasUsed) + enc.ParentBeaconBlockRoot = s.ParentBeaconBlockRoot return json.Marshal(&enc) } // UnmarshalJSON unmarshals from JSON. func (s *stEnv) UnmarshalJSON(input []byte) error { type stEnv struct { - Coinbase *common.UnprefixedAddress `json:"currentCoinbase" gencodec:"required"` - Difficulty *math.HexOrDecimal256 `json:"currentDifficulty"` - Random *math.HexOrDecimal256 `json:"currentRandom"` - ParentDifficulty *math.HexOrDecimal256 `json:"parentDifficulty"` - ParentBaseFee *math.HexOrDecimal256 `json:"parentBaseFee,omitempty"` - ParentGasUsed *math.HexOrDecimal64 `json:"parentGasUsed,omitempty"` - ParentGasLimit *math.HexOrDecimal64 `json:"parentGasLimit,omitempty"` - GasLimit *math.HexOrDecimal64 `json:"currentGasLimit" gencodec:"required"` - Number *math.HexOrDecimal64 `json:"currentNumber" gencodec:"required"` - Timestamp *math.HexOrDecimal64 `json:"currentTimestamp" gencodec:"required"` - ParentTimestamp *math.HexOrDecimal64 `json:"parentTimestamp,omitempty"` - BlockHashes map[math.HexOrDecimal64]common.Hash `json:"blockHashes,omitempty"` - Ommers []ommer `json:"ommers,omitempty"` - Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"` - BaseFee *math.HexOrDecimal256 `json:"currentBaseFee,omitempty"` - ParentUncleHash *common.Hash `json:"parentUncleHash"` + Coinbase *common.UnprefixedAddress `json:"currentCoinbase" gencodec:"required"` + Difficulty *math.HexOrDecimal256 `json:"currentDifficulty"` + Random *math.HexOrDecimal256 `json:"currentRandom"` + ParentDifficulty *math.HexOrDecimal256 `json:"parentDifficulty"` + ParentBaseFee *math.HexOrDecimal256 `json:"parentBaseFee,omitempty"` + ParentGasUsed *math.HexOrDecimal64 `json:"parentGasUsed,omitempty"` + ParentGasLimit *math.HexOrDecimal64 `json:"parentGasLimit,omitempty"` + GasLimit *math.HexOrDecimal64 `json:"currentGasLimit" gencodec:"required"` + Number *math.HexOrDecimal64 `json:"currentNumber" gencodec:"required"` + Timestamp *math.HexOrDecimal64 `json:"currentTimestamp" gencodec:"required"` + ParentTimestamp *math.HexOrDecimal64 `json:"parentTimestamp,omitempty"` + BlockHashes map[math.HexOrDecimal64]common.Hash `json:"blockHashes,omitempty"` + Ommers []ommer `json:"ommers,omitempty"` + Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"` + BaseFee *math.HexOrDecimal256 `json:"currentBaseFee,omitempty"` + ParentUncleHash *common.Hash `json:"parentUncleHash"` + ExcessBlobGas *math.HexOrDecimal64 `json:"excessBlobGas,omitempty"` + ParentExcessBlobGas *math.HexOrDecimal64 `json:"parentExcessBlobGas,omitempty"` + ParentBlobGasUsed *math.HexOrDecimal64 `json:"parentBlobGasUsed,omitempty"` + ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot"` } var dec stEnv if err := json.Unmarshal(input, &dec); err != nil { @@ -130,5 +142,17 @@ func (s *stEnv) UnmarshalJSON(input []byte) error { if dec.ParentUncleHash != nil { s.ParentUncleHash = *dec.ParentUncleHash } + if dec.ExcessBlobGas != nil { + s.ExcessBlobGas = (*uint64)(dec.ExcessBlobGas) + } + if dec.ParentExcessBlobGas != nil { + s.ParentExcessBlobGas = (*uint64)(dec.ParentExcessBlobGas) + } + if dec.ParentBlobGasUsed != nil { + s.ParentBlobGasUsed = (*uint64)(dec.ParentBlobGasUsed) + } + if dec.ParentBeaconBlockRoot != nil { + s.ParentBeaconBlockRoot = dec.ParentBeaconBlockRoot + } return nil } diff --git a/cmd/evm/internal/t8ntool/transaction.go b/cmd/evm/internal/t8ntool/transaction.go index b1f65815b7..03a2e2eb99 100644 --- a/cmd/evm/internal/t8ntool/transaction.go +++ b/cmd/evm/internal/t8ntool/transaction.go @@ -140,7 +140,7 @@ func Transaction(ctx *cli.Context) error { } // Check intrinsic gas if gas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, - chainConfig.IsHomestead(new(big.Int)), chainConfig.IsIstanbul(new(big.Int)), chainConfig.IsShanghai(0)); err != nil { + chainConfig.IsHomestead(new(big.Int)), chainConfig.IsIstanbul(new(big.Int)), chainConfig.IsShanghai(new(big.Int), 0)); err != nil { r.Error = err results = append(results, r) continue @@ -172,7 +172,7 @@ func Transaction(ctx *cli.Context) error { r.Error = errors.New("gas * maxFeePerGas exceeds 256 bits") } // Check whether the init code size has been exceeded. - if chainConfig.IsShanghai(0) && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSize { + if chainConfig.IsShanghai(new(big.Int), 0) && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSize { r.Error = errors.New("max initcode size exceeded") } results = append(results, r) diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go index a5d061292f..396b341d2e 100644 --- a/cmd/evm/internal/t8ntool/transition.go +++ b/cmd/evm/internal/t8ntool/transition.go @@ -28,7 +28,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/consensus/misc" + "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/types" @@ -192,105 +192,20 @@ func Transition(ctx *cli.Context) error { // Set the chain id chainConfig.ChainID = big.NewInt(ctx.Int64(ChainIDFlag.Name)) - var txsWithKeys []*txWithKey - if txStr != stdinSelector { - inFile, err := os.Open(txStr) - if err != nil { - return NewError(ErrorIO, fmt.Errorf("failed reading txs file: %v", err)) - } - defer inFile.Close() - decoder := json.NewDecoder(inFile) - if strings.HasSuffix(txStr, ".rlp") { - var body hexutil.Bytes - if err := decoder.Decode(&body); err != nil { - return err - } - var txs types.Transactions - if err := rlp.DecodeBytes(body, &txs); err != nil { - return err - } - for _, tx := range txs { - txsWithKeys = append(txsWithKeys, &txWithKey{ - key: nil, - tx: tx, - }) - } - } else { - if err := decoder.Decode(&txsWithKeys); err != nil { - return NewError(ErrorJson, fmt.Errorf("failed unmarshaling txs-file: %v", err)) - } - } - } else { - if len(inputData.TxRlp) > 0 { - // Decode the body of already signed transactions - body := common.FromHex(inputData.TxRlp) - var txs types.Transactions - if err := rlp.DecodeBytes(body, &txs); err != nil { - return err - } - for _, tx := range txs { - txsWithKeys = append(txsWithKeys, &txWithKey{ - key: nil, - tx: tx, - }) - } - } else { - // JSON encoded transactions - txsWithKeys = inputData.Txs - } + if txs, err = loadTransactions(txStr, inputData, prestate.Env, chainConfig); err != nil { + return err } - // We may have to sign the transactions. - signer := types.MakeSigner(chainConfig, big.NewInt(int64(prestate.Env.Number)), prestate.Env.Timestamp) - - if txs, err = signUnsignedTransactions(txsWithKeys, signer); err != nil { - return NewError(ErrorJson, fmt.Errorf("failed signing transactions: %v", err)) + if err := applyLondonChecks(&prestate.Env, chainConfig); err != nil { + return err } - // Sanity check, to not `panic` in state_transition - if chainConfig.IsLondon(big.NewInt(int64(prestate.Env.Number))) { - if prestate.Env.BaseFee != nil { - // Already set, base fee has precedent over parent base fee. - } else if prestate.Env.ParentBaseFee != nil && prestate.Env.Number != 0 { - parent := &types.Header{ - Number: new(big.Int).SetUint64(prestate.Env.Number - 1), - BaseFee: prestate.Env.ParentBaseFee, - GasUsed: prestate.Env.ParentGasUsed, - GasLimit: prestate.Env.ParentGasLimit, - } - prestate.Env.BaseFee = misc.CalcBaseFee(chainConfig, parent) - } else { - return NewError(ErrorConfig, errors.New("EIP-1559 config but missing 'currentBaseFee' in env section")) - } + if err := applyShanghaiChecks(&prestate.Env, chainConfig); err != nil { + return err } - if chainConfig.IsShanghai(prestate.Env.Number) && prestate.Env.Withdrawals == nil { - return NewError(ErrorConfig, errors.New("Shanghai config but missing 'withdrawals' in env section")) + if err := applyMergeChecks(&prestate.Env, chainConfig); err != nil { + return err } - isMerged := chainConfig.TerminalTotalDifficulty != nil && chainConfig.TerminalTotalDifficulty.BitLen() == 0 - env := prestate.Env - if isMerged { - // post-merge: - // - random must be supplied - // - difficulty must be zero - switch { - case env.Random == nil: - return NewError(ErrorConfig, errors.New("post-merge requires currentRandom to be defined in env")) - case env.Difficulty != nil && env.Difficulty.BitLen() != 0: - return NewError(ErrorConfig, errors.New("post-merge difficulty must be zero (or omitted) in env")) - } - prestate.Env.Difficulty = nil - } else if env.Difficulty == nil { - // pre-merge: - // If difficulty was not provided by caller, we need to calculate it. - switch { - case env.ParentDifficulty == nil: - return NewError(ErrorConfig, errors.New("currentDifficulty was not provided, and cannot be calculated due to missing parentDifficulty")) - case env.Number == 0: - return NewError(ErrorConfig, errors.New("currentDifficulty needs to be provided for block number 0")) - case env.Timestamp <= env.ParentTimestamp: - return NewError(ErrorConfig, fmt.Errorf("currentDifficulty cannot be calculated -- currentTime (%d) needs to be after parent time (%d)", - env.Timestamp, env.ParentTimestamp)) - } - prestate.Env.Difficulty = calcDifficulty(chainConfig, env.Number, env.Timestamp, - env.ParentTimestamp, env.ParentDifficulty, env.ParentUncleHash) + if err := applyCancunChecks(&prestate.Env, chainConfig); err != nil { + return err } // Run the test and aggregate the result s, result, err := prestate.Apply(vmConfig, chainConfig, txs, ctx.Int64(RewardFlag.Name), getTracer) @@ -358,38 +273,157 @@ func (t *txWithKey) UnmarshalJSON(input []byte) error { // and secondly to read them with the standard tx json format func signUnsignedTransactions(txs []*txWithKey, signer types.Signer) (types.Transactions, error) { var signedTxs []*types.Transaction - for i, txWithKey := range txs { - tx := txWithKey.tx - key := txWithKey.key - v, r, s := tx.RawSignatureValues() - if key != nil && v.BitLen()+r.BitLen()+s.BitLen() == 0 { - // This transaction needs to be signed - var ( - signed *types.Transaction - err error - ) - if txWithKey.protected { - signed, err = types.SignTx(tx, signer, key) - } else { - signed, err = types.SignTx(tx, types.FrontierSigner{}, key) - } - if err != nil { - return nil, NewError(ErrorJson, fmt.Errorf("tx %d: failed to sign tx: %v", i, err)) - } - signedTxs = append(signedTxs, signed) - } else { + for i, tx := range txs { + var ( + v, r, s = tx.tx.RawSignatureValues() + signed *types.Transaction + err error + ) + if tx.key == nil || v.BitLen()+r.BitLen()+s.BitLen() != 0 { // Already signed - signedTxs = append(signedTxs, tx) + signedTxs = append(signedTxs, tx.tx) + continue } + // This transaction needs to be signed + if tx.protected { + signed, err = types.SignTx(tx.tx, signer, tx.key) + } else { + signed, err = types.SignTx(tx.tx, types.FrontierSigner{}, tx.key) + } + if err != nil { + return nil, NewError(ErrorJson, fmt.Errorf("tx %d: failed to sign tx: %v", i, err)) + } + signedTxs = append(signedTxs, signed) } return signedTxs, nil } +func loadTransactions(txStr string, inputData *input, env stEnv, chainConfig *params.ChainConfig) (types.Transactions, error) { + var txsWithKeys []*txWithKey + var signed types.Transactions + if txStr != stdinSelector { + data, err := os.ReadFile(txStr) + if err != nil { + return nil, NewError(ErrorIO, fmt.Errorf("failed reading txs file: %v", err)) + } + if strings.HasSuffix(txStr, ".rlp") { // A file containing an rlp list + var body hexutil.Bytes + if err := json.Unmarshal(data, &body); err != nil { + return nil, err + } + // Already signed transactions + if err := rlp.DecodeBytes(body, &signed); err != nil { + return nil, err + } + return signed, nil + } + if err := json.Unmarshal(data, &txsWithKeys); err != nil { + return nil, NewError(ErrorJson, fmt.Errorf("failed unmarshaling txs-file: %v", err)) + } + } else { + if len(inputData.TxRlp) > 0 { + // Decode the body of already signed transactions + body := common.FromHex(inputData.TxRlp) + // Already signed transactions + if err := rlp.DecodeBytes(body, &signed); err != nil { + return nil, err + } + return signed, nil + } + // JSON encoded transactions + txsWithKeys = inputData.Txs + } + // We may have to sign the transactions. + signer := types.MakeSigner(chainConfig, big.NewInt(int64(env.Number)), env.Timestamp) + return signUnsignedTransactions(txsWithKeys, signer) +} + +func applyLondonChecks(env *stEnv, chainConfig *params.ChainConfig) error { + if !chainConfig.IsLondon(big.NewInt(int64(env.Number))) { + return nil + } + // Sanity check, to not `panic` in state_transition + if env.BaseFee != nil { + // Already set, base fee has precedent over parent base fee. + return nil + } + if env.ParentBaseFee == nil || env.Number == 0 { + return NewError(ErrorConfig, errors.New("EIP-1559 config but missing 'currentBaseFee' in env section")) + } + env.BaseFee = eip1559.CalcBaseFee(chainConfig, &types.Header{ + Number: new(big.Int).SetUint64(env.Number - 1), + BaseFee: env.ParentBaseFee, + GasUsed: env.ParentGasUsed, + GasLimit: env.ParentGasLimit, + }) + return nil +} + +func applyShanghaiChecks(env *stEnv, chainConfig *params.ChainConfig) error { + if !chainConfig.IsShanghai(big.NewInt(int64(env.Number)), env.Timestamp) { + return nil + } + if env.Withdrawals == nil { + return NewError(ErrorConfig, errors.New("Shanghai config but missing 'withdrawals' in env section")) + } + return nil +} + +func applyMergeChecks(env *stEnv, chainConfig *params.ChainConfig) error { + isMerged := chainConfig.TerminalTotalDifficulty != nil && chainConfig.TerminalTotalDifficulty.BitLen() == 0 + if !isMerged { + // pre-merge: If difficulty was not provided by caller, we need to calculate it. + if env.Difficulty != nil { + // already set + return nil + } + switch { + case env.ParentDifficulty == nil: + return NewError(ErrorConfig, errors.New("currentDifficulty was not provided, and cannot be calculated due to missing parentDifficulty")) + case env.Number == 0: + return NewError(ErrorConfig, errors.New("currentDifficulty needs to be provided for block number 0")) + case env.Timestamp <= env.ParentTimestamp: + return NewError(ErrorConfig, fmt.Errorf("currentDifficulty cannot be calculated -- currentTime (%d) needs to be after parent time (%d)", + env.Timestamp, env.ParentTimestamp)) + } + env.Difficulty = calcDifficulty(chainConfig, env.Number, env.Timestamp, + env.ParentTimestamp, env.ParentDifficulty, env.ParentUncleHash) + return nil + } + // post-merge: + // - random must be supplied + // - difficulty must be zero + switch { + case env.Random == nil: + return NewError(ErrorConfig, errors.New("post-merge requires currentRandom to be defined in env")) + case env.Difficulty != nil && env.Difficulty.BitLen() != 0: + return NewError(ErrorConfig, errors.New("post-merge difficulty must be zero (or omitted) in env")) + } + env.Difficulty = nil + return nil +} + +func applyCancunChecks(env *stEnv, chainConfig *params.ChainConfig) error { + if !chainConfig.IsCancun(big.NewInt(int64(env.Number)), env.Timestamp) { + env.ParentBeaconBlockRoot = nil // un-set it if it has been set too early + return nil + } + // Post-cancun + // We require EIP-4788 beacon root to be set in the env + if env.ParentBeaconBlockRoot == nil { + return NewError(ErrorConfig, errors.New("post-cancun env requires parentBeaconBlockRoot to be set")) + } + return nil +} + type Alloc map[common.Address]core.GenesisAccount func (g Alloc) OnRoot(common.Hash) {} -func (g Alloc) OnAccount(addr common.Address, dumpAccount state.DumpAccount) { +func (g Alloc) OnAccount(addr *common.Address, dumpAccount state.DumpAccount) { + if addr == nil { + return + } balance, _ := new(big.Int).SetString(dumpAccount.Balance, 10) var storage map[common.Hash]common.Hash if dumpAccount.Storage != nil { @@ -404,7 +438,7 @@ func (g Alloc) OnAccount(addr common.Address, dumpAccount state.DumpAccount) { Balance: balance, Nonce: dumpAccount.Nonce, } - g[addr] = genesisAccount + g[*addr] = genesisAccount } // saveFile marshals the object to the given file diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go index 52d7c3fa30..ac8432badb 100644 --- a/cmd/evm/runner.go +++ b/cmd/evm/runner.go @@ -42,6 +42,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/trie" + "github.com/ethereum/go-ethereum/trie/triedb/hashdb" "github.com/urfave/cli/v2" ) @@ -128,6 +129,7 @@ func runCmd(ctx *cli.Context) error { receiver = common.BytesToAddress([]byte("receiver")) genesisConfig *core.Genesis preimages = ctx.Bool(DumpFlag.Name) + blobHashes []common.Hash // TODO (MariusVanDerWijden) implement blob hashes in state tests ) if ctx.Bool(MachineFlag.Name) { tracer = logger.NewJSONLogger(logconfig, os.Stdout) @@ -141,12 +143,23 @@ func runCmd(ctx *cli.Context) error { gen := readGenesis(ctx.String(GenesisFlag.Name)) genesisConfig = gen db := rawdb.NewMemoryDatabase() - genesis := gen.MustCommit(db) - sdb := state.NewDatabaseWithConfig(db, &trie.Config{Preimages: preimages}) + triedb := trie.NewDatabase(db, &trie.Config{ + Preimages: preimages, + HashDB: hashdb.Defaults, + }) + defer triedb.Close() + genesis := gen.MustCommit(db, triedb) + sdb := state.NewDatabaseWithNodeDB(db, triedb) statedb, _ = state.New(genesis.Root(), sdb, nil) chainConfig = gen.Config } else { - sdb := state.NewDatabaseWithConfig(rawdb.NewMemoryDatabase(), &trie.Config{Preimages: preimages}) + db := rawdb.NewMemoryDatabase() + triedb := trie.NewDatabase(db, &trie.Config{ + Preimages: preimages, + HashDB: hashdb.Defaults, + }) + defer triedb.Close() + sdb := state.NewDatabaseWithNodeDB(db, triedb) statedb, _ = state.New(types.EmptyRootHash, sdb, nil) genesisConfig = new(core.Genesis) } @@ -217,6 +230,7 @@ func runCmd(ctx *cli.Context) error { Time: genesisConfig.Timestamp, Coinbase: genesisConfig.Coinbase, BlockNumber: new(big.Int).SetUint64(genesisConfig.Number), + BlobHashes: blobHashes, EVMConfig: vm.Config{ Tracer: tracer, }, @@ -278,8 +292,7 @@ func runCmd(ctx *cli.Context) error { output, leftOverGas, stats, err := timedExec(bench, execFunc) if ctx.Bool(DumpFlag.Name) { - statedb.Commit(true) - statedb.IntermediateRoot(true) + statedb.Commit(genesisConfig.Number, true) fmt.Println(string(statedb.Dump(nil))) } diff --git a/cmd/evm/staterunner.go b/cmd/evm/staterunner.go index e9229eaeca..85931f0406 100644 --- a/cmd/evm/staterunner.go +++ b/cmd/evm/staterunner.go @@ -17,13 +17,15 @@ package main import ( + "bufio" "encoding/json" - "errors" "fmt" "os" "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/state/snapshot" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/tracers/logger" "github.com/ethereum/go-ethereum/log" @@ -34,7 +36,7 @@ import ( var stateTestCommand = &cli.Command{ Action: stateTestCmd, Name: "statetest", - Usage: "executes the given state tests", + Usage: "Executes the given state tests. Filenames can be fed via standard input (batch mode) or as an argument (one-off execution).", ArgsUsage: "", } @@ -50,9 +52,6 @@ type StatetestResult struct { } func stateTestCmd(ctx *cli.Context) error { - if len(ctx.Args().First()) == 0 { - return errors.New("path-to-test argument required") - } // Configure the go-ethereum logger glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false))) glogger.Verbosity(log.Lvl(ctx.Int(VerbosityFlag.Name))) @@ -65,66 +64,66 @@ func stateTestCmd(ctx *cli.Context) error { DisableStorage: ctx.Bool(DisableStorageFlag.Name), EnableReturnData: !ctx.Bool(DisableReturnDataFlag.Name), } - var ( - tracer vm.EVMLogger - debugger *logger.StructLogger - ) + var cfg vm.Config switch { case ctx.Bool(MachineFlag.Name): - tracer = logger.NewJSONLogger(config, os.Stderr) + cfg.Tracer = logger.NewJSONLogger(config, os.Stderr) case ctx.Bool(DebugFlag.Name): - debugger = logger.NewStructLogger(config) - tracer = debugger - - default: - debugger = logger.NewStructLogger(config) + cfg.Tracer = logger.NewStructLogger(config) } // Load the test content from the input file - src, err := os.ReadFile(ctx.Args().First()) + if len(ctx.Args().First()) != 0 { + return runStateTest(ctx.Args().First(), cfg, ctx.Bool(MachineFlag.Name), ctx.Bool(DumpFlag.Name)) + } + // Read filenames from stdin and execute back-to-back + scanner := bufio.NewScanner(os.Stdin) + for scanner.Scan() { + fname := scanner.Text() + if len(fname) == 0 { + return nil + } + if err := runStateTest(fname, cfg, ctx.Bool(MachineFlag.Name), ctx.Bool(DumpFlag.Name)); err != nil { + return err + } + } + return nil +} + +// runStateTest loads the state-test given by fname, and executes the test. +func runStateTest(fname string, cfg vm.Config, jsonOut, dump bool) error { + src, err := os.ReadFile(fname) if err != nil { return err } var tests map[string]tests.StateTest - if err = json.Unmarshal(src, &tests); err != nil { + if err := json.Unmarshal(src, &tests); err != nil { return err } // Iterate over all the tests, run them and aggregate the results - cfg := vm.Config{ - Tracer: tracer, - } results := make([]StatetestResult, 0, len(tests)) for key, test := range tests { for _, st := range test.Subtests() { // Run the test and aggregate the result result := &StatetestResult{Name: key, Fork: st.Fork, Pass: true} - _, s, err := test.Run(st, cfg, false) - // print state root for evmlab tracing - if s != nil { - root := s.IntermediateRoot(false) - result.Root = &root - if ctx.Bool(MachineFlag.Name) { - fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%#x\"}\n", root) + test.Run(st, cfg, false, rawdb.HashScheme, func(err error, snaps *snapshot.Tree, state *state.StateDB) { + if state != nil { + root := state.IntermediateRoot(false) + result.Root = &root + if jsonOut { + fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%#x\"}\n", root) + } } - } - if err != nil { - // Test failed, mark as so and dump any state to aid debugging - result.Pass, result.Error = false, err.Error() - if ctx.Bool(DumpFlag.Name) && s != nil { - dump := s.RawDump(nil) - result.State = &dump + if err != nil { + // Test failed, mark as so and dump any state to aid debugging + result.Pass, result.Error = false, err.Error() + if dump { + dump := state.RawDump(nil) + result.State = &dump + } } - } - + }) results = append(results, *result) - - // Print any structured logs collected - if ctx.Bool(DebugFlag.Name) { - if debugger != nil { - fmt.Fprintln(os.Stderr, "#### TRACE ####") - logger.WriteTrace(os.Stderr, debugger.StructLogs()) - } - } } } out, _ := json.MarshalIndent(results, "", " ") diff --git a/cmd/evm/t8n_test.go b/cmd/evm/t8n_test.go index 0ef3fac409..ad09a6b4d6 100644 --- a/cmd/evm/t8n_test.go +++ b/cmd/evm/t8n_test.go @@ -259,6 +259,22 @@ func TestT8n(t *testing.T) { output: t8nOutput{alloc: true, result: true}, expOut: "exp.json", }, + { // Cancun tests + base: "./testdata/28", + input: t8nInput{ + "alloc.json", "txs.rlp", "env.json", "Cancun", "", + }, + output: t8nOutput{alloc: true, result: true}, + expOut: "exp.json", + }, + { // More cancun tests + base: "./testdata/29", + input: t8nInput{ + "alloc.json", "txs.json", "env.json", "Cancun", "", + }, + output: t8nOutput{alloc: true, result: true}, + expOut: "exp.json", + }, } { args := []string{"t8n"} args = append(args, tc.output.get()...) diff --git a/cmd/evm/testdata/13/readme.md b/cmd/evm/testdata/13/readme.md index 64f52fc9a9..889975d47e 100644 --- a/cmd/evm/testdata/13/readme.md +++ b/cmd/evm/testdata/13/readme.md @@ -1,4 +1,4 @@ ## Input transactions in RLP form -This testdata folder is used to examplify how transaction input can be provided in rlp form. +This testdata folder is used to exemplify how transaction input can be provided in rlp form. Please see the README in `evm` folder for how this is performed. \ No newline at end of file diff --git a/cmd/evm/testdata/2/readme.md b/cmd/evm/testdata/2/readme.md index c116f0e792..4bcf0f0fa0 100644 --- a/cmd/evm/testdata/2/readme.md +++ b/cmd/evm/testdata/2/readme.md @@ -1 +1 @@ -These files examplify a selfdestruct to the `0`-address. \ No newline at end of file +These files exemplify a selfdestruct to the `0`-address. \ No newline at end of file diff --git a/cmd/evm/testdata/23/readme.md b/cmd/evm/testdata/23/readme.md index 85fe8db66c..f31b64de2f 100644 --- a/cmd/evm/testdata/23/readme.md +++ b/cmd/evm/testdata/23/readme.md @@ -1 +1 @@ -These files examplify how to sign a transaction using the pre-EIP155 scheme. +These files exemplify how to sign a transaction using the pre-EIP155 scheme. diff --git a/cmd/evm/testdata/28/alloc.json b/cmd/evm/testdata/28/alloc.json new file mode 100644 index 0000000000..680a89f4ed --- /dev/null +++ b/cmd/evm/testdata/28/alloc.json @@ -0,0 +1,16 @@ +{ + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "0x016345785d8a0000", + "code" : "0x", + "nonce" : "0x00", + "storage" : { + } + }, + "0xb94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "0x016345785d8a0000", + "code" : "0x60004960015500", + "nonce" : "0x00", + "storage" : { + } + } +} \ No newline at end of file diff --git a/cmd/evm/testdata/28/env.json b/cmd/evm/testdata/28/env.json new file mode 100644 index 0000000000..5056fe29a4 --- /dev/null +++ b/cmd/evm/testdata/28/env.json @@ -0,0 +1,23 @@ +{ + "currentCoinbase" : "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentNumber" : "0x01", + "currentTimestamp" : "0x079e", + "currentGasLimit" : "0x7fffffffffffffff", + "previousHash" : "0x3a9b485972e7353edd9152712492f0c58d89ef80623686b6bf947a4a6dce6cb6", + "currentBlobGasUsed" : "0x00", + "parentTimestamp" : "0x03b6", + "parentDifficulty" : "0x00", + "parentUncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "currentRandom" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "withdrawals" : [ + ], + "parentBaseFee" : "0x0a", + "parentGasUsed" : "0x00", + "parentGasLimit" : "0x7fffffffffffffff", + "parentExcessBlobGas" : "0x00", + "parentBlobGasUsed" : "0x00", + "blockHashes" : { + "0" : "0x3a9b485972e7353edd9152712492f0c58d89ef80623686b6bf947a4a6dce6cb6" + }, + "parentBeaconBlockRoot": "0x0000beac00beac00beac00beac00beac00beac00beac00beac00beac00beac00" +} \ No newline at end of file diff --git a/cmd/evm/testdata/28/exp.json b/cmd/evm/testdata/28/exp.json new file mode 100644 index 0000000000..a55ce0aec4 --- /dev/null +++ b/cmd/evm/testdata/28/exp.json @@ -0,0 +1,47 @@ +{ + "alloc": { + "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba": { + "balance": "0x150ca" + }, + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "balance": "0x16345785d80c3a9", + "nonce": "0x1" + }, + "0xb94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "code": "0x60004960015500", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x01a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8" + }, + "balance": "0x16345785d8a0000" + } + }, + "result": { + "stateRoot": "0xa40cb3fab01848e922a48bd24191815df9f721ad4b60376edac75161517663e8", + "txRoot": "0x4409cc4b699384ba5f8248d92b784713610c5ff9c1de51e9239da0dac76de9ce", + "receiptsRoot": "0xbff643da765981266133094092d98c81d2ac8e9a83a7bbda46c3d736f1f874ac", + "logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "receipts": [ + { + "type": "0x3", + "root": "0x", + "status": "0x1", + "cumulativeGasUsed": "0xa865", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "logs": null, + "transactionHash": "0x7508d7139d002a4b3a26a4f12dec0d87cb46075c78bf77a38b569a133b509262", + "contractAddress": "0x0000000000000000000000000000000000000000", + "gasUsed": "0xa865", + "effectiveGasPrice": null, + "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "transactionIndex": "0x0" + } + ], + "currentDifficulty": null, + "gasUsed": "0xa865", + "currentBaseFee": "0x9", + "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "currentExcessBlobGas": "0x0", + "currentBlobGasUsed": "0x20000" + } +} \ No newline at end of file diff --git a/cmd/evm/testdata/28/txs.rlp b/cmd/evm/testdata/28/txs.rlp new file mode 100644 index 0000000000..8df20e3aa2 --- /dev/null +++ b/cmd/evm/testdata/28/txs.rlp @@ -0,0 +1 @@ +"0xf88bb88903f8860180026483061a8094b94f5374fce5edbc8e2a8697c15331677e6ebf0b8080c00ae1a001a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d801a025e16bb498552165016751911c3608d79000ab89dc3100776e729e6ea13091c7a03acacff7fc0cff6eda8a927dec93ca17765e1ee6cbc06c5954ce102e097c01d2" \ No newline at end of file diff --git a/cmd/evm/testdata/29/alloc.json b/cmd/evm/testdata/29/alloc.json new file mode 100644 index 0000000000..70d47862a0 --- /dev/null +++ b/cmd/evm/testdata/29/alloc.json @@ -0,0 +1,16 @@ +{ + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "0x016345785d8a0000", + "code" : "0x", + "nonce" : "0x00", + "storage" : { + } + }, + "0xbEac00dDB15f3B6d645C48263dC93862413A222D" : { + "balance" : "0x1", + "code" : "0x3373fffffffffffffffffffffffffffffffffffffffe14604457602036146024575f5ffd5b620180005f350680545f35146037575f5ffd5b6201800001545f5260205ff35b6201800042064281555f359062018000015500", + "nonce" : "0x00", + "storage" : { + } + } +} \ No newline at end of file diff --git a/cmd/evm/testdata/29/env.json b/cmd/evm/testdata/29/env.json new file mode 100644 index 0000000000..e752a909ad --- /dev/null +++ b/cmd/evm/testdata/29/env.json @@ -0,0 +1,20 @@ +{ + "currentCoinbase" : "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentNumber" : "0x01", + "currentTimestamp" : "0x079e", + "currentGasLimit" : "0x7fffffffffffffff", + "previousHash" : "0x3a9b485972e7353edd9152712492f0c58d89ef80623686b6bf947a4a6dce6cb6", + "currentBlobGasUsed" : "0x00", + "parentTimestamp" : "0x03b6", + "parentDifficulty" : "0x00", + "parentUncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "currentRandom" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "withdrawals" : [ + ], + "parentBaseFee" : "0x0a", + "parentGasUsed" : "0x00", + "parentGasLimit" : "0x7fffffffffffffff", + "parentExcessBlobGas" : "0x00", + "parentBlobGasUsed" : "0x00", + "parentBeaconBlockRoot": "0x0000beac00beac00beac00beac00beac00beac00beac00beac00beac00beac00" +} \ No newline at end of file diff --git a/cmd/evm/testdata/29/exp.json b/cmd/evm/testdata/29/exp.json new file mode 100644 index 0000000000..16a8817774 --- /dev/null +++ b/cmd/evm/testdata/29/exp.json @@ -0,0 +1,45 @@ +{ + "alloc": { + "0xbeac00ddb15f3b6d645c48263dc93862413a222d": { + "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604457602036146024575f5ffd5b620180005f350680545f35146037575f5ffd5b6201800001545f5260205ff35b6201800042064281555f359062018000015500", + "storage": { + "0x000000000000000000000000000000000000000000000000000000000000079e": "0x000000000000000000000000000000000000000000000000000000000000079e", + "0x000000000000000000000000000000000000000000000000000000000001879e": "0x0000beac00beac00beac00beac00beac00beac00beac00beac00beac00beac00" + }, + "balance": "0x1" + }, + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "balance": "0x16345785d871db8", + "nonce": "0x1" + } + }, + "result": { + "stateRoot": "0x2db9f6bc233e8fd0af2d8023404493a19b37d9d69ace71f4e73158851fced574", + "txRoot": "0x248074fabe112f7d93917f292b64932394f835bb98da91f21501574d58ec92ab", + "receiptsRoot": "0xf78dfb743fbd92ade140711c8bbc542b5e307f0ab7984eff35d751969fe57efa", + "logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "receipts": [ + { + "type": "0x2", + "root": "0x", + "status": "0x1", + "cumulativeGasUsed": "0x5208", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "logs": null, + "transactionHash": "0x84f70aba406a55628a0620f26d260f90aeb6ccc55fed6ec2ac13dd4f727032ed", + "contractAddress": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x5208", + "effectiveGasPrice": null, + "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "transactionIndex": "0x0" + } + ], + "currentDifficulty": null, + "gasUsed": "0x5208", + "currentBaseFee": "0x9", + "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "currentExcessBlobGas": "0x0", + "currentBlobGasUsed": "0x0" + } +} \ No newline at end of file diff --git a/cmd/evm/testdata/29/readme.md b/cmd/evm/testdata/29/readme.md new file mode 100644 index 0000000000..4383e328ed --- /dev/null +++ b/cmd/evm/testdata/29/readme.md @@ -0,0 +1,29 @@ +## EIP 4788 + +This test contains testcases for EIP-4788. The 4788-contract is +located at address `0xbeac00ddb15f3b6d645c48263dc93862413a222d`, and this test executes a simple transaction. It also +implicitly invokes the system tx, which sets calls the contract and sets the +storage values +``` +$ dir=./testdata/29/ && go run . t8n --state.fork=Cancun --input.alloc=$dir/alloc.json --input.txs=$dir/txs.json --input.env=$dir/env.json --output.alloc=stdout +INFO [08-15|20:07:56.335] Trie dumping started root=ecde45..2af8a7 +INFO [08-15|20:07:56.335] Trie dumping complete accounts=2 elapsed="225.848µs" +INFO [08-15|20:07:56.335] Wrote file file=result.json +{ + "alloc": { + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "balance": "0x16345785d871db8", + "nonce": "0x1" + }, + "0xbeac00541d49391ed88abf392bfc1f4dea8c4143": { + "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604457602036146024575f5ffd5b620180005f350680545f35146037575f5ffd5b6201800001545f5260205ff35b6201800042064281555f359062018000015500", + "storage": { + "0x000000000000000000000000000000000000000000000000000000000000079e": "0x000000000000000000000000000000000000000000000000000000000000079e", + "0x000000000000000000000000000000000000000000000000000000000001879e": "0x0000beac00beac00beac00beac00beac00beac00beac00beac00beac00beac00" + }, + "balance": "0x + } + } +} + +``` diff --git a/cmd/evm/testdata/29/txs.json b/cmd/evm/testdata/29/txs.json new file mode 100644 index 0000000000..d6743cc4d2 --- /dev/null +++ b/cmd/evm/testdata/29/txs.json @@ -0,0 +1,19 @@ +[ + { + "input" : "0x", + "gas" : "0x10000000", + "nonce" : "0x0", + "to" : "0x1111111111111111111111111111111111111111", + "value" : "0x0", + "secretKey" : "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "chainId" : "0x1", + "type" : "0x2", + "v": "0x0", + "r": "0x0", + "s": "0x0", + "maxFeePerGas" : "0xfa0", + "maxPriorityFeePerGas" : "0x0", + "accessList" : [ + ] + } +] \ No newline at end of file diff --git a/cmd/evm/testdata/3/readme.md b/cmd/evm/testdata/3/readme.md index 499f03d7aa..246c58ef3b 100644 --- a/cmd/evm/testdata/3/readme.md +++ b/cmd/evm/testdata/3/readme.md @@ -1,2 +1,2 @@ -These files examplify a transition where a transaction (excuted on block 5) requests +These files exemplify a transition where a transaction (executed on block 5) requests the blockhash for block `1`. diff --git a/cmd/evm/testdata/4/readme.md b/cmd/evm/testdata/4/readme.md index 08840d37bd..eede41a9fd 100644 --- a/cmd/evm/testdata/4/readme.md +++ b/cmd/evm/testdata/4/readme.md @@ -1,3 +1,3 @@ -These files examplify a transition where a transaction (excuted on block 5) requests +These files exemplify a transition where a transaction (executed on block 5) requests the blockhash for block `4`, but where the hash for that block is missing. It's expected that executing these should cause `exit` with errorcode `4`. diff --git a/cmd/evm/testdata/5/readme.md b/cmd/evm/testdata/5/readme.md index e2b608face..1a84afaab6 100644 --- a/cmd/evm/testdata/5/readme.md +++ b/cmd/evm/testdata/5/readme.md @@ -1 +1 @@ -These files examplify a transition where there are no transcations, two ommers, at block `N-1` (delta 1) and `N-2` (delta 2). \ No newline at end of file +These files exemplify a transition where there are no transactions, two ommers, at block `N-1` (delta 1) and `N-2` (delta 2). \ No newline at end of file diff --git a/cmd/evm/testdata/8/readme.md b/cmd/evm/testdata/8/readme.md index c991fb2177..4dffdab91e 100644 --- a/cmd/evm/testdata/8/readme.md +++ b/cmd/evm/testdata/8/readme.md @@ -7,7 +7,7 @@ This test contains testcases for EIP-2930, which uses transactions with access l The alloc portion contains one contract (`0x000000000000000000000000000000000000aaaa`), containing the following code: `0x5854505854`: `PC ;SLOAD; POP; PC; SLOAD`. -Essentialy, this contract does `SLOAD(0)` and `SLOAD(3)`. +Essentially, this contract does `SLOAD(0)` and `SLOAD(3)`. The alloc also contains some funds on `0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b`. diff --git a/cmd/evm/testdata/9/readme.md b/cmd/evm/testdata/9/readme.md index b144644655..5394780288 100644 --- a/cmd/evm/testdata/9/readme.md +++ b/cmd/evm/testdata/9/readme.md @@ -7,7 +7,7 @@ This test contains testcases for EIP-1559, which uses an new transaction type an The alloc portion contains one contract (`0x000000000000000000000000000000000000aaaa`), containing the following code: `0x58585454`: `PC; PC; SLOAD; SLOAD`. -Essentialy, this contract does `SLOAD(0)` and `SLOAD(1)`. +Essentially, this contract does `SLOAD(0)` and `SLOAD(1)`. The alloc also contains some funds on `0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b`. diff --git a/cmd/evm/transition-test.sh b/cmd/evm/transition-test.sh index a2ea534189..8cc6aa41de 100644 --- a/cmd/evm/transition-test.sh +++ b/cmd/evm/transition-test.sh @@ -280,7 +280,7 @@ To make `t8n` apply these, the following inputs are required: - For ethash, it is `5000000000000000000` `wei`, - If this is not defined, mining rewards are not applied, - A value of `0` is valid, and causes accounts to be 'touched'. -- For each ommer, the tool needs to be given an `addres\` and a `delta`. This +- For each ommer, the tool needs to be given an `address\` and a `delta`. This is done via the `ommers` field in `env`. Note: the tool does not verify that e.g. the normal uncle rules apply, diff --git a/cmd/faucet/README.md b/cmd/faucet/README.md index 6e9b14ebc7..7e857fa0ee 100644 --- a/cmd/faucet/README.md +++ b/cmd/faucet/README.md @@ -12,7 +12,6 @@ First things first, the `faucet` needs to connect to an Ethereum network, for wh - `-genesis` is a path to a file containing the network `genesis.json`. or using: - `-goerli` with the faucet with Görli network config - - `-rinkeby` with the faucet with Rinkeby network config - `-sepolia` with the faucet with Sepolia network config - `-network` is the devp2p network id used during connection - `-bootnodes` is a list of `enode://` ids to join the network through diff --git a/cmd/faucet/faucet.go b/cmd/faucet/faucet.go index 3dfd639144..e4d6ad6977 100644 --- a/cmd/faucet/faucet.go +++ b/cmd/faucet/faucet.go @@ -86,7 +86,6 @@ var ( twitterTokenV1Flag = flag.String("twitter.token.v1", "", "Bearer token to authenticate with the v1.1 Twitter API") goerliFlag = flag.Bool("goerli", false, "Initializes the faucet with Görli network config") - rinkebyFlag = flag.Bool("rinkeby", false, "Initializes the faucet with Rinkeby network config") sepoliaFlag = flag.Bool("sepolia", false, "Initializes the faucet with Sepolia network config") ) @@ -140,7 +139,7 @@ func main() { log.Crit("Failed to render the faucet template", "err", err) } // Load and parse the genesis block requested by the user - genesis, err := getGenesis(*genesisFlag, *goerliFlag, *rinkebyFlag, *sepoliaFlag) + genesis, err := getGenesis(*genesisFlag, *goerliFlag, *sepoliaFlag) if err != nil { log.Crit("Failed to parse genesis config", "err", err) } @@ -269,11 +268,7 @@ func newFaucet(genesis *core.Genesis, port int, enodes []*enode.Node, network ui } } // Attach to the client and retrieve and interesting metadatas - api, err := stack.Attach() - if err != nil { - stack.Close() - return nil, err - } + api := stack.Attach() client := ethclient.NewClient(api) return &faucet{ @@ -880,7 +875,7 @@ func authNoAuth(url string) (string, string, common.Address, error) { } // getGenesis returns a genesis based on input args -func getGenesis(genesisFlag string, goerliFlag bool, rinkebyFlag bool, sepoliaFlag bool) (*core.Genesis, error) { +func getGenesis(genesisFlag string, goerliFlag bool, sepoliaFlag bool) (*core.Genesis, error) { switch { case genesisFlag != "": var genesis core.Genesis @@ -888,11 +883,9 @@ func getGenesis(genesisFlag string, goerliFlag bool, rinkebyFlag bool, sepoliaFl return &genesis, err case goerliFlag: return core.DefaultGoerliGenesisBlock(), nil - case rinkebyFlag: - return core.DefaultRinkebyGenesisBlock(), nil case sepoliaFlag: return core.DefaultSepoliaGenesisBlock(), nil default: - return nil, fmt.Errorf("no genesis flag provided") + return nil, errors.New("no genesis flag provided") } } diff --git a/cmd/geth/attach_test.go b/cmd/geth/attach_test.go index 7c5f951750..91007ccf65 100644 --- a/cmd/geth/attach_test.go +++ b/cmd/geth/attach_test.go @@ -61,7 +61,7 @@ func TestRemoteDbWithHeaders(t *testing.T) { } func testReceiveHeaders(t *testing.T, ln net.Listener, gethArgs ...string) { - var ok uint32 + var ok atomic.Uint32 server := &http.Server{ Addr: "localhost:0", Handler: &testHandler{func(w http.ResponseWriter, r *http.Request) { @@ -72,12 +72,12 @@ func testReceiveHeaders(t *testing.T, ln net.Listener, gethArgs ...string) { if have, want := r.Header.Get("second"), "two"; have != want { t.Fatalf("missing header, have %v want %v", have, want) } - atomic.StoreUint32(&ok, 1) + ok.Store(1) }}} go server.Serve(ln) defer server.Close() runGeth(t, gethArgs...).WaitExit() - if atomic.LoadUint32(&ok) != 1 { + if ok.Load() != 1 { t.Fatal("Test fail, expected invocation to succeed") } } diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index 96999075a3..fad2c71e68 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -39,7 +39,6 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/trie" "github.com/urfave/cli/v2" ) @@ -49,7 +48,10 @@ var ( Name: "init", Usage: "Bootstrap and initialize a new genesis block", ArgsUsage: "", - Flags: flags.Merge([]cli.Flag{utils.CachePreimagesFlag}, utils.DatabasePathFlags), + Flags: flags.Merge([]cli.Flag{ + utils.CachePreimagesFlag, + utils.StateSchemeFlag, + }, utils.DatabasePathFlags), Description: ` The init command initializes a new genesis block and definition for the network. This is a destructive action and changes the network in which you will be @@ -94,6 +96,9 @@ if one is set. Otherwise it prints the genesis from the datadir.`, utils.MetricsInfluxDBBucketFlag, utils.MetricsInfluxDBOrganizationFlag, utils.TxLookupLimitFlag, + utils.TransactionHistoryFlag, + utils.StateSchemeFlag, + utils.StateHistoryFlag, }, utils.DatabasePathFlags), Description: ` The import command imports blocks from an RLP-encoded form. The form can be one file @@ -110,6 +115,7 @@ processing will proceed even if an individual RLP-file import failure occurs.`, Flags: flags.Merge([]cli.Flag{ utils.CacheFlag, utils.SyncModeFlag, + utils.StateSchemeFlag, }, utils.DatabasePathFlags), Description: ` Requires a first argument of the file to write to. @@ -159,6 +165,7 @@ It's deprecated, please use "geth db export" instead. utils.IncludeIncompletesFlag, utils.StartKeyFlag, utils.DumpLimitFlag, + utils.StateSchemeFlag, }, utils.DatabasePathFlags), Description: ` This command dumps out the state for a given block (or latest, if none provided). @@ -195,14 +202,15 @@ func initGenesis(ctx *cli.Context) error { if err != nil { utils.Fatalf("Failed to open database: %v", err) } - triedb := trie.NewDatabaseWithConfig(chaindb, &trie.Config{ - Preimages: ctx.Bool(utils.CachePreimagesFlag.Name), - }) + defer chaindb.Close() + + triedb := utils.MakeTrieDatabase(ctx, chaindb, ctx.Bool(utils.CachePreimagesFlag.Name), false) + defer triedb.Close() + _, hash, err := core.SetupGenesisBlock(chaindb, triedb, genesis) if err != nil { utils.Fatalf("Failed to write genesis block: %v", err) } - chaindb.Close() log.Info("Successfully wrote genesis state", "database", name, "hash", hash) } return nil @@ -241,7 +249,7 @@ func dumpGenesis(ctx *cli.Context) error { if ctx.IsSet(utils.DataDirFlag.Name) { utils.Fatalf("no existing datadir at %s", stack.Config().DataDir) } - utils.Fatalf("no network preset provided. no exisiting genesis in the default datadir") + utils.Fatalf("no network preset provided, no existing genesis in the default datadir") return nil } @@ -261,16 +269,16 @@ func importChain(ctx *cli.Context) error { defer db.Close() // Start periodically gathering memory profiles - var peakMemAlloc, peakMemSys uint64 + var peakMemAlloc, peakMemSys atomic.Uint64 go func() { stats := new(runtime.MemStats) for { runtime.ReadMemStats(stats) - if atomic.LoadUint64(&peakMemAlloc) < stats.Alloc { - atomic.StoreUint64(&peakMemAlloc, stats.Alloc) + if peakMemAlloc.Load() < stats.Alloc { + peakMemAlloc.Store(stats.Alloc) } - if atomic.LoadUint64(&peakMemSys) < stats.Sys { - atomic.StoreUint64(&peakMemSys, stats.Sys) + if peakMemSys.Load() < stats.Sys { + peakMemSys.Store(stats.Sys) } time.Sleep(5 * time.Second) } @@ -303,8 +311,8 @@ func importChain(ctx *cli.Context) error { mem := new(runtime.MemStats) runtime.ReadMemStats(mem) - fmt.Printf("Object memory: %.3f MB current, %.3f MB peak\n", float64(mem.Alloc)/1024/1024, float64(atomic.LoadUint64(&peakMemAlloc))/1024/1024) - fmt.Printf("System memory: %.3f MB current, %.3f MB peak\n", float64(mem.Sys)/1024/1024, float64(atomic.LoadUint64(&peakMemSys))/1024/1024) + fmt.Printf("Object memory: %.3f MB current, %.3f MB peak\n", float64(mem.Alloc)/1024/1024, float64(peakMemAlloc.Load())/1024/1024) + fmt.Printf("System memory: %.3f MB current, %.3f MB peak\n", float64(mem.Sys)/1024/1024, float64(peakMemSys.Load())/1024/1024) fmt.Printf("Allocations: %.3f million\n", float64(mem.Mallocs)/1000000) fmt.Printf("GC pause: %v\n\n", time.Duration(mem.PauseTotalNs)) @@ -465,10 +473,10 @@ func dump(ctx *cli.Context) error { if err != nil { return err } - config := &trie.Config{ - Preimages: true, // always enable preimage lookup - } - state, err := state.New(root, state.NewDatabaseWithConfig(db, config), nil) + triedb := utils.MakeTrieDatabase(ctx, db, true, false) // always enable preimage lookup + defer triedb.Close() + + state, err := state.New(root, state.NewDatabaseWithNodeDB(db, triedb), nil) if err != nil { return err } @@ -478,7 +486,7 @@ func dump(ctx *cli.Context) error { if conf.OnlyWithAddresses { fmt.Fprintf(os.Stderr, "If you want to include accounts with missing preimages, you need iterative output, since"+ " otherwise the accounts will overwrite each other in the resulting mapping.") - return fmt.Errorf("incompatible options") + return errors.New("incompatible options") } fmt.Println(string(state.Dump(conf))) } diff --git a/cmd/geth/config.go b/cmd/geth/config.go index 42ded49322..2761ee7453 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -22,16 +22,17 @@ import ( "fmt" "os" "reflect" + "runtime" + "strings" "unicode" - "github.com/urfave/cli/v2" - "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/external" "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/cmd/utils" + "github.com/ethereum/go-ethereum/eth/catalyst" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/internal/ethapi" @@ -42,6 +43,7 @@ import ( "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/params" "github.com/naoina/toml" + "github.com/urfave/cli/v2" ) var ( @@ -170,8 +172,26 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) { v := ctx.Uint64(utils.OverrideCancun.Name) cfg.Eth.OverrideCancun = &v } + if ctx.IsSet(utils.OverrideVerkle.Name) { + 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 + if eth != nil { // The 'eth' backend may be nil in light mode + var protos []string + for _, p := range eth.Protocols() { + protos = append(protos, fmt.Sprintf("%v/%d", p.Name, p.Version)) + } + metrics.NewRegisteredGaugeInfo("geth/info", nil).Update(metrics.GaugeInfoValue{ + "arch": runtime.GOARCH, + "os": runtime.GOOS, + "version": cfg.Node.Version, + "eth_protocols": strings.Join(protos, ","), + }) + } + // Configure log filter RPC API. filterSystem := utils.RegisterFilterAPI(stack, backend, &cfg.Eth) @@ -189,6 +209,22 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) { if ctx.IsSet(utils.SyncTargetFlag.Name) && cfg.Eth.SyncMode == downloader.FullSync { utils.RegisterFullSyncTester(stack, eth, ctx.Path(utils.SyncTargetFlag.Name)) } + + // Start the dev mode if requested, or launch the engine API for + // interacting with external consensus client. + if ctx.IsSet(utils.DeveloperFlag.Name) { + simBeacon, err := catalyst.NewSimulatedBeacon(ctx.Uint64(utils.DeveloperPeriodFlag.Name), eth) + if err != nil { + utils.Fatalf("failed to register dev mode catalyst service: %v", err) + } + catalyst.RegisterSimulatedBeaconAPIs(stack, simBeacon) + stack.RegisterLifecycle(simBeacon) + } else if cfg.Eth.SyncMode != downloader.LightSync { + err := catalyst.Register(stack, eth) + if err != nil { + utils.Fatalf("failed to register catalyst service: %v", err) + } + } return stack, backend } @@ -272,6 +308,10 @@ func deprecated(field string) bool { return true case "ethconfig.Config.EWASMInterpreter": return true + case "ethconfig.Config.TrieCleanCacheJournal": + return true + case "ethconfig.Config.TrieCleanCacheRejournal": + return true default: return false } diff --git a/cmd/geth/consolecmd.go b/cmd/geth/consolecmd.go index aeee6f9c9e..526ede9619 100644 --- a/cmd/geth/consolecmd.go +++ b/cmd/geth/consolecmd.go @@ -75,10 +75,7 @@ func localConsole(ctx *cli.Context) error { defer stack.Close() // Attach to the newly started node and create the JavaScript console. - client, err := stack.Attach() - if err != nil { - return fmt.Errorf("failed to attach to the inproc geth: %v", err) - } + client := stack.Attach() config := console.Config{ DataDir: utils.MakeDataDir(ctx), DocRoot: ctx.String(utils.JSpathFlag.Name), diff --git a/cmd/geth/consolecmd_test.go b/cmd/geth/consolecmd_test.go index 46bdf3c90d..5046906c0a 100644 --- a/cmd/geth/consolecmd_test.go +++ b/cmd/geth/consolecmd_test.go @@ -116,7 +116,7 @@ func TestAttachWelcome(t *testing.T) { waitForEndpoint(t, endpoint, 3*time.Second) testAttachWelcome(t, geth, endpoint, httpAPIs) }) - geth.ExpectExit() + geth.Kill() } func testAttachWelcome(t *testing.T, geth *testgeth, endpoint, apis string) { diff --git a/cmd/geth/dbcmd.go b/cmd/geth/dbcmd.go index b409b19260..a1868eb8c3 100644 --- a/cmd/geth/dbcmd.go +++ b/cmd/geth/dbcmd.go @@ -151,6 +151,7 @@ WARNING: This is a low-level operation which may cause database corruption!`, ArgsUsage: " ", Flags: flags.Merge([]cli.Flag{ utils.SyncModeFlag, + utils.StateSchemeFlag, }, utils.NetworkFlags, utils.DatabasePathFlags), Description: "This command looks up the specified database key from the database.", } @@ -482,6 +483,9 @@ func dbDumpTrie(ctx *cli.Context) error { db := utils.MakeChainDatabase(ctx, stack, true) defer db.Close() + triedb := utils.MakeTrieDatabase(ctx, db, false, true) + defer triedb.Close() + var ( state []byte storage []byte @@ -515,12 +519,16 @@ func dbDumpTrie(ctx *cli.Context) error { } } id := trie.StorageTrieID(common.BytesToHash(state), common.BytesToHash(account), common.BytesToHash(storage)) - theTrie, err := trie.New(id, trie.NewDatabase(db)) + theTrie, err := trie.New(id, triedb) + if err != nil { + return err + } + trieIt, err := theTrie.NodeIterator(start) if err != nil { return err } var count int64 - it := trie.NewIterator(theTrie.NodeIterator(start)) + it := trie.NewIterator(trieIt) for it.Next() { if max > 0 && count == max { fmt.Printf("Exiting after %d values\n", count) diff --git a/cmd/geth/genesis_test.go b/cmd/geth/genesis_test.go index ffe8176b01..2506b42d1e 100644 --- a/cmd/geth/genesis_test.go +++ b/cmd/geth/genesis_test.go @@ -176,12 +176,12 @@ func TestCustomBackend(t *testing.T) { { // Can't start pebble on top of leveldb initArgs: []string{"--db.engine", "leveldb"}, execArgs: []string{"--db.engine", "pebble"}, - execExpect: `Fatal: Failed to register the Ethereum service: db.engine choice was pebble but found pre-existing leveldb database in specified data directory`, + execExpect: `Fatal: Could not open database: db.engine choice was pebble but found pre-existing leveldb database in specified data directory`, }, { // Can't start leveldb on top of pebble initArgs: []string{"--db.engine", "pebble"}, execArgs: []string{"--db.engine", "leveldb"}, - execExpect: `Fatal: Failed to register the Ethereum service: db.engine choice was leveldb but found pre-existing pebble database in specified data directory`, + execExpect: `Fatal: Could not open database: db.engine choice was leveldb but found pre-existing pebble database in specified data directory`, }, { // Reject invalid backend choice initArgs: []string{"--db.engine", "mssql"}, diff --git a/cmd/geth/les_test.go b/cmd/geth/les_test.go index 607b454ead..b36c3265a3 100644 --- a/cmd/geth/les_test.go +++ b/cmd/geth/les_test.go @@ -107,10 +107,10 @@ func ipcEndpoint(ipcPath, datadir string) string { // but windows require pipes to sit in "\\.\pipe\". Therefore, to run several // nodes simultaneously, we need to distinguish between them, which we do by // the pipe filename instead of folder. -var nextIPC = uint32(0) +var nextIPC atomic.Uint32 func startGethWithIpc(t *testing.T, name string, args ...string) *gethrpc { - ipcName := fmt.Sprintf("geth-%d.ipc", atomic.AddUint32(&nextIPC, 1)) + ipcName := fmt.Sprintf("geth-%d.ipc", nextIPC.Add(1)) args = append([]string{"--networkid=42", "--port=0", "--authrpc.port", "0", "--ipcpath", ipcName}, args...) t.Logf("Starting %v with rpc: %v", name, args) @@ -146,13 +146,13 @@ func startLightServer(t *testing.T) *gethrpc { t.Logf("Importing keys to geth") runGeth(t, "account", "import", "--datadir", datadir, "--password", "./testdata/password.txt", "--lightkdf", "./testdata/key.prv").WaitExit() account := "0x02f0d131f1f97aef08aec6e3291b957d9efe7105" - server := startGethWithIpc(t, "lightserver", "--allow-insecure-unlock", "--datadir", datadir, "--password", "./testdata/password.txt", "--unlock", account, "--miner.etherbase=0x02f0d131f1f97aef08aec6e3291b957d9efe7105", "--mine", "--light.serve=100", "--light.maxpeers=1", "--nodiscover", "--nat=extip:127.0.0.1", "--verbosity=4") + server := startGethWithIpc(t, "lightserver", "--allow-insecure-unlock", "--datadir", datadir, "--password", "./testdata/password.txt", "--unlock", account, "--miner.etherbase=0x02f0d131f1f97aef08aec6e3291b957d9efe7105", "--mine", "--light.serve=100", "--light.maxpeers=1", "--discv4=false", "--nat=extip:127.0.0.1", "--verbosity=4") return server } func startClient(t *testing.T, name string) *gethrpc { datadir := initGeth(t) - return startGethWithIpc(t, name, "--datadir", datadir, "--nodiscover", "--syncmode=light", "--nat=extip:127.0.0.1", "--verbosity=4") + return startGethWithIpc(t, name, "--datadir", datadir, "--discv4=false", "--syncmode=light", "--nat=extip:127.0.0.1", "--verbosity=4") } func TestPriorityClient(t *testing.T) { diff --git a/cmd/geth/main.go b/cmd/geth/main.go index b4a7b5fa95..09730a7716 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -39,6 +39,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/node" + "go.uber.org/automaxprocs/maxprocs" // Force-load the tracer engines to trigger registration _ "github.com/ethereum/go-ethereum/eth/tracers/js" @@ -65,6 +66,7 @@ var ( utils.USBFlag, utils.SmartCardDaemonPathFlag, utils.OverrideCancun, + utils.OverrideVerkle, utils.EnablePersonal, utils.TxPoolLocalsFlag, utils.TxPoolNoLocalsFlag, @@ -77,21 +79,24 @@ var ( utils.TxPoolAccountQueueFlag, utils.TxPoolGlobalQueueFlag, utils.TxPoolLifetimeFlag, + utils.BlobPoolDataDirFlag, + utils.BlobPoolDataCapFlag, + utils.BlobPoolPriceBumpFlag, utils.SyncModeFlag, utils.SyncTargetFlag, utils.ExitWhenSyncedFlag, utils.GCModeFlag, utils.SnapshotFlag, utils.TxLookupLimitFlag, + utils.TransactionHistoryFlag, + utils.StateSchemeFlag, + utils.StateHistoryFlag, utils.LightServeFlag, utils.LightIngressFlag, utils.LightEgressFlag, utils.LightMaxPeersFlag, utils.LightNoPruneFlag, utils.LightKDFFlag, - utils.UltraLightServersFlag, - utils.UltraLightFractionFlag, - utils.UltraLightOnlyAnnounceFlag, utils.LightNoSyncServeFlag, utils.EthRequiredBlocksFlag, utils.LegacyWhitelistFlag, @@ -121,14 +126,16 @@ var ( utils.MinerNewPayloadTimeout, utils.NATFlag, utils.NoDiscoverFlag, + utils.DiscoveryV4Flag, utils.DiscoveryV5Flag, + utils.LegacyDiscoveryV5Flag, utils.NetrestrictFlag, utils.NodeKeyFileFlag, utils.NodeKeyHexFlag, utils.DNSDiscoveryFlag, utils.DeveloperFlag, - utils.DeveloperPeriodFlag, utils.DeveloperGasLimitFlag, + utils.DeveloperPeriodFlag, utils.VMEnableDebugFlag, utils.NetworkIdFlag, utils.EthStatsURLFlag, @@ -168,6 +175,8 @@ var ( utils.RPCGlobalEVMTimeoutFlag, utils.RPCGlobalTxFeeCapFlag, utils.AllowUnprotectedTxs, + utils.BatchRequestLimit, + utils.BatchResponseMaxSize, } metricsFlags = []cli.Flag{ @@ -237,6 +246,7 @@ func init() { ) app.Before = func(ctx *cli.Context) error { + maxprocs.Set() // Automatically set GOMAXPROCS to match Linux container CPU quota. flags.MigrateGlobalFlags(ctx) return debug.Setup(ctx) } @@ -259,15 +269,15 @@ func main() { func prepare(ctx *cli.Context) { // If we're running a known preset, log it for convenience. switch { - case ctx.IsSet(utils.RinkebyFlag.Name): - log.Info("Starting Geth on Rinkeby testnet...") - 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...") + case ctx.IsSet(utils.HoleskyFlag.Name): + log.Info("Starting Geth on Holesky testnet...") + case ctx.IsSet(utils.DeveloperFlag.Name): log.Info("Starting Geth in ephemeral dev mode...") log.Warn(`You are running Geth in --dev mode. Please note the following: @@ -292,8 +302,8 @@ func prepare(ctx *cli.Context) { // If we're a full node on mainnet without --cache specified, bump default cache allowance if ctx.String(utils.SyncModeFlag.Name) != "light" && !ctx.IsSet(utils.CacheFlag.Name) && !ctx.IsSet(utils.NetworkIdFlag.Name) { // Make sure we're not on any supported preconfigured testnet either - if !ctx.IsSet(utils.SepoliaFlag.Name) && - !ctx.IsSet(utils.RinkebyFlag.Name) && + 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! @@ -348,10 +358,7 @@ func startNode(ctx *cli.Context, stack *node.Node, backend ethapi.Backend, isCon stack.AccountManager().Subscribe(events) // Create a client to interact with local geth node. - rpcClient, err := stack.Attach() - if err != nil { - utils.Fatalf("Failed to attach to self: %v", err) - } + rpcClient := stack.Attach() ethClient := ethclient.NewClient(rpcClient) go func() { @@ -412,7 +419,7 @@ func startNode(ctx *cli.Context, stack *node.Node, backend ethapi.Backend, isCon } // Start auxiliary services if enabled - if ctx.Bool(utils.MiningEnabledFlag.Name) || ctx.Bool(utils.DeveloperFlag.Name) { + 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") @@ -423,7 +430,7 @@ func startNode(ctx *cli.Context, stack *node.Node, backend ethapi.Backend, isCon } // Set the gas price to the limits from the CLI and start mining gasprice := flags.GlobalBig(ctx, utils.MinerGasPriceFlag.Name) - ethBackend.TxPool().SetGasPrice(gasprice) + ethBackend.TxPool().SetGasTip(gasprice) if err := ethBackend.StartMining(); err != nil { utils.Fatalf("Failed to start mining: %v", err) } diff --git a/cmd/geth/snapshot.go b/cmd/geth/snapshot.go index 0759341fd9..5e1c784730 100644 --- a/cmd/geth/snapshot.go +++ b/cmd/geth/snapshot.go @@ -50,7 +50,6 @@ var ( ArgsUsage: "", Action: pruneState, Flags: flags.Merge([]cli.Flag{ - utils.CacheTrieJournalFlag, utils.BloomFilterSizeFlag, }, utils.NetworkFlags, utils.DatabasePathFlags), Description: ` @@ -62,10 +61,7 @@ two version states are available: genesis and the specific one. The default pruning target is the HEAD-127 state. -WARNING: It's necessary to delete the trie clean cache after the pruning. -If you specify another directory for the trie clean cache via "--cache.trie.journal" -during the use of Geth, please also specify it here for correct deletion. Otherwise -the trie clean cache with default directory will be deleted. +WARNING: it's only supported in hash mode(--state.scheme=hash)". `, }, { @@ -73,7 +69,9 @@ the trie clean cache with default directory will be deleted. Usage: "Recalculate state hash based on the snapshot for verification", ArgsUsage: "", Action: verifyState, - Flags: flags.Merge(utils.NetworkFlags, utils.DatabasePathFlags), + Flags: flags.Merge([]cli.Flag{ + utils.StateSchemeFlag, + }, utils.NetworkFlags, utils.DatabasePathFlags), Description: ` geth snapshot verify-state will traverse the whole accounts and storages set based on the specified @@ -108,7 +106,9 @@ information about the specified address. Usage: "Traverse the state with given root hash and perform quick verification", ArgsUsage: "", Action: traverseState, - Flags: flags.Merge(utils.NetworkFlags, utils.DatabasePathFlags), + Flags: flags.Merge([]cli.Flag{ + utils.StateSchemeFlag, + }, utils.NetworkFlags, utils.DatabasePathFlags), Description: ` geth snapshot traverse-state will traverse the whole state from the given state root and will abort if any @@ -123,7 +123,9 @@ It's also usable without snapshot enabled. Usage: "Traverse the state with given root hash and perform detailed verification", ArgsUsage: "", Action: traverseRawState, - Flags: flags.Merge(utils.NetworkFlags, utils.DatabasePathFlags), + Flags: flags.Merge([]cli.Flag{ + utils.StateSchemeFlag, + }, utils.NetworkFlags, utils.DatabasePathFlags), Description: ` geth snapshot traverse-rawstate will traverse the whole state from the given root and will abort if any referenced @@ -144,6 +146,7 @@ It's also usable without snapshot enabled. utils.ExcludeStorageFlag, utils.StartKeyFlag, utils.DumpLimitFlag, + utils.StateSchemeFlag, }, utils.NetworkFlags, utils.DatabasePathFlags), Description: ` This command is semantically equivalent to 'geth dump', but uses the snapshots @@ -160,15 +163,17 @@ block is used. // Deprecation: this command should be deprecated once the hash-based // scheme is deprecated. func pruneState(ctx *cli.Context) error { - stack, config := makeConfigNode(ctx) + stack, _ := makeConfigNode(ctx) defer stack.Close() chaindb := utils.MakeChainDatabase(ctx, stack, false) defer chaindb.Close() + if rawdb.ReadStateScheme(chaindb) != rawdb.HashScheme { + log.Crit("Offline pruning is not required for path scheme") + } prunerconfig := pruner.Config{ Datadir: stack.ResolvePath(""), - Cachedir: stack.ResolvePath(config.Eth.TrieCleanCacheJournal), BloomSize: ctx.Uint64(utils.BloomFilterSizeFlag.Name), } pruner, err := pruner.NewPruner(chaindb, prunerconfig) @@ -207,13 +212,16 @@ func verifyState(ctx *cli.Context) error { log.Error("Failed to load head block") return errors.New("no head block") } - snapconfig := snapshot.Config{ + triedb := utils.MakeTrieDatabase(ctx, chaindb, false, true) + defer triedb.Close() + + snapConfig := snapshot.Config{ CacheSize: 256, Recovery: false, NoBuild: true, AsyncBuild: false, } - snaptree, err := snapshot.New(snapconfig, chaindb, trie.NewDatabase(chaindb), headBlock.Root()) + snaptree, err := snapshot.New(snapConfig, chaindb, triedb, headBlock.Root()) if err != nil { log.Error("Failed to open snapshot tree", "err", err) return err @@ -255,6 +263,11 @@ func traverseState(ctx *cli.Context) error { defer stack.Close() chaindb := utils.MakeChainDatabase(ctx, stack, true) + defer chaindb.Close() + + triedb := utils.MakeTrieDatabase(ctx, chaindb, false, true) + defer triedb.Close() + headBlock := rawdb.ReadHeadBlock(chaindb) if headBlock == nil { log.Error("Failed to load head block") @@ -279,7 +292,6 @@ func traverseState(ctx *cli.Context) error { root = headBlock.Root() log.Info("Start traversing the state", "root", root, "number", headBlock.NumberU64()) } - triedb := trie.NewDatabase(chaindb) t, err := trie.NewStateTrie(trie.StateTrieID(root), triedb) if err != nil { log.Error("Failed to open trie", "root", root, "err", err) @@ -292,7 +304,12 @@ func traverseState(ctx *cli.Context) error { lastReport time.Time start = time.Now() ) - accIter := trie.NewIterator(t.NodeIterator(nil)) + acctIt, err := t.NodeIterator(nil) + if err != nil { + log.Error("Failed to open iterator", "root", root, "err", err) + return err + } + accIter := trie.NewIterator(acctIt) for accIter.Next() { accounts += 1 var acc types.StateAccount @@ -307,7 +324,12 @@ func traverseState(ctx *cli.Context) error { log.Error("Failed to open storage trie", "root", acc.Root, "err", err) return err } - storageIter := trie.NewIterator(storageTrie.NodeIterator(nil)) + storageIt, err := storageTrie.NodeIterator(nil) + if err != nil { + log.Error("Failed to open storage iterator", "root", acc.Root, "err", err) + return err + } + storageIter := trie.NewIterator(storageIt) for storageIter.Next() { slots += 1 } @@ -345,6 +367,11 @@ func traverseRawState(ctx *cli.Context) error { defer stack.Close() chaindb := utils.MakeChainDatabase(ctx, stack, true) + defer chaindb.Close() + + triedb := utils.MakeTrieDatabase(ctx, chaindb, false, true) + defer triedb.Close() + headBlock := rawdb.ReadHeadBlock(chaindb) if headBlock == nil { log.Error("Failed to load head block") @@ -369,7 +396,6 @@ func traverseRawState(ctx *cli.Context) error { root = headBlock.Root() log.Info("Start traversing the state", "root", root, "number", headBlock.NumberU64()) } - triedb := trie.NewDatabase(chaindb) t, err := trie.NewStateTrie(trie.StateTrieID(root), triedb) if err != nil { log.Error("Failed to open trie", "root", root, "err", err) @@ -385,7 +411,16 @@ func traverseRawState(ctx *cli.Context) error { hasher = crypto.NewKeccakState() got = make([]byte, 32) ) - accIter := t.NodeIterator(nil) + accIter, err := t.NodeIterator(nil) + if err != nil { + log.Error("Failed to open iterator", "root", root, "err", err) + return err + } + reader, err := triedb.Reader(root) + if err != nil { + log.Error("State is non-existent", "root", root) + return nil + } for accIter.Next(true) { nodes += 1 node := accIter.Hash() @@ -393,7 +428,7 @@ func traverseRawState(ctx *cli.Context) error { // Check the present for non-empty hash node(embedded node doesn't // have their own hash). if node != (common.Hash{}) { - blob := rawdb.ReadLegacyTrieNode(chaindb, node) + blob, _ := reader.Node(common.Hash{}, accIter.Path(), node) if len(blob) == 0 { log.Error("Missing trie node(account)", "hash", node) return errors.New("missing account") @@ -422,7 +457,11 @@ func traverseRawState(ctx *cli.Context) error { log.Error("Failed to open storage trie", "root", acc.Root, "err", err) return errors.New("missing storage trie") } - storageIter := storageTrie.NodeIterator(nil) + storageIter, err := storageTrie.NodeIterator(nil) + if err != nil { + log.Error("Failed to open storage iterator", "root", acc.Root, "err", err) + return err + } for storageIter.Next(true) { nodes += 1 node := storageIter.Hash() @@ -430,7 +469,7 @@ func traverseRawState(ctx *cli.Context) error { // Check the presence for non-empty hash node(embedded node doesn't // have their own hash). if node != (common.Hash{}) { - blob := rawdb.ReadLegacyTrieNode(chaindb, node) + blob, _ := reader.Node(common.BytesToHash(accIter.LeafKey()), storageIter.Path(), node) if len(blob) == 0 { log.Error("Missing trie node(storage)", "hash", node) return errors.New("missing storage") @@ -490,13 +529,16 @@ func dumpState(ctx *cli.Context) error { if err != nil { return err } + triedb := utils.MakeTrieDatabase(ctx, db, false, true) + defer triedb.Close() + snapConfig := snapshot.Config{ CacheSize: 256, Recovery: false, NoBuild: true, AsyncBuild: false, } - snaptree, err := snapshot.New(snapConfig, db, trie.NewDatabase(db), root) + snaptree, err := snapshot.New(snapConfig, db, triedb, root) if err != nil { return err } @@ -517,14 +559,14 @@ func dumpState(ctx *cli.Context) error { Root common.Hash `json:"root"` }{root}) for accIt.Next() { - account, err := snapshot.FullAccount(accIt.Account()) + account, err := types.FullAccount(accIt.Account()) if err != nil { return err } da := &state.DumpAccount{ Balance: account.Balance.String(), Nonce: account.Nonce, - Root: account.Root, + Root: account.Root.Bytes(), CodeHash: account.CodeHash, SecureKey: accIt.Hash().Bytes(), } diff --git a/cmd/geth/testdata/vcheck/minisig-sigs-new/data.json.minisig b/cmd/geth/testdata/vcheck/minisig-sigs-new/data.json.minisig new file mode 100644 index 0000000000..eaea9f9053 --- /dev/null +++ b/cmd/geth/testdata/vcheck/minisig-sigs-new/data.json.minisig @@ -0,0 +1,4 @@ +untrusted comment: signature from minisign secret key +RUQkliYstQBOKLK05Sy5f3bVRMBqJT26ABo6Vbp3BNJAVjejoqYCu4GWE/+7qcDfHBqYIniDCbFIUvYEnOHxV6vZ93wO1xJWDQw= +trusted comment: timestamp:1693986492 file:data.json hashed +6Fdw2H+W1ZXK7QXSF77Z5AWC7+AEFAfDmTSxNGylU5HLT1AuSJQmxslj+VjtUBamYCvOuET7plbXza942AlWDw== diff --git a/cmd/geth/verkle.go b/cmd/geth/verkle.go index a5756ceab0..9ba2b41671 100644 --- a/cmd/geth/verkle.go +++ b/cmd/geth/verkle.go @@ -74,7 +74,7 @@ func checkChildren(root verkle.VerkleNode, resolver verkle.NodeResolverFn) error switch node := root.(type) { case *verkle.InternalNode: for i, child := range node.Children() { - childC := child.ComputeCommitment().Bytes() + childC := child.Commit().Bytes() childS, err := resolver(childC[:]) if bytes.Equal(childC[:], zero[:]) { @@ -86,7 +86,7 @@ func checkChildren(root verkle.VerkleNode, resolver verkle.NodeResolverFn) error // depth is set to 0, the tree isn't rebuilt so it's not a problem childN, err := verkle.ParseNode(childS, 0, childC[:]) if err != nil { - return fmt.Errorf("decode error child %x in db: %w", child.ComputeCommitment().Bytes(), err) + return fmt.Errorf("decode error child %x in db: %w", child.Commitment().Bytes(), err) } if err := checkChildren(childN, resolver); err != nil { return fmt.Errorf("%x%w", i, err) // write the path to the erroring node @@ -100,7 +100,7 @@ func checkChildren(root verkle.VerkleNode, resolver verkle.NodeResolverFn) error return nil } } - return fmt.Errorf("Both balance and nonce are 0") + return errors.New("both balance and nonce are 0") case verkle.Empty: // nothing to do default: diff --git a/cmd/geth/version_check_test.go b/cmd/geth/version_check_test.go index bd4d820a79..4458ab5c06 100644 --- a/cmd/geth/version_check_test.go +++ b/cmd/geth/version_check_test.go @@ -30,17 +30,24 @@ import ( ) func TestVerification(t *testing.T) { - // Signatures generated with `minisign` - t.Run("minisig", func(t *testing.T) { - // For this test, the pubkey is in testdata/minisign.pub + // Signatures generated with `minisign`. Legacy format, not pre-hashed file. + t.Run("minisig-legacy", func(t *testing.T) { + // For this test, the pubkey is in testdata/vcheck/minisign.pub // (the privkey is `minisign.sec`, if we want to expand this test. Password 'test' ) pub := "RWQkliYstQBOKOdtClfgC3IypIPX6TAmoEi7beZ4gyR3wsaezvqOMWsp" testVerification(t, pub, "./testdata/vcheck/minisig-sigs/") }) + t.Run("minisig-new", func(t *testing.T) { + // For this test, the pubkey is in testdata/vcheck/minisign.pub + // (the privkey is `minisign.sec`, if we want to expand this test. Password 'test' ) + // `minisign -S -s ./minisign.sec -m data.json -x ./minisig-sigs-new/data.json.minisig` + pub := "RWQkliYstQBOKOdtClfgC3IypIPX6TAmoEi7beZ4gyR3wsaezvqOMWsp" + testVerification(t, pub, "./testdata/vcheck/minisig-sigs-new/") + }) // Signatures generated with `signify-openbsd` t.Run("signify-openbsd", func(t *testing.T) { t.Skip("This currently fails, minisign expects 4 lines of data, signify provides only 2") - // For this test, the pubkey is in testdata/signifykey.pub + // For this test, the pubkey is in testdata/vcheck/signifykey.pub // (the privkey is `signifykey.sec`, if we want to expand this test. Password 'test' ) pub := "RWSKLNhZb0KdATtRT7mZC/bybI3t3+Hv/O2i3ye04Dq9fnT9slpZ1a2/" testVerification(t, pub, "./testdata/vcheck/signify-sigs/") @@ -58,6 +65,9 @@ func testVerification(t *testing.T, pubkey, sigdir string) { if err != nil { t.Fatal(err) } + if len(files) == 0 { + t.Fatal("Missing tests") + } for _, f := range files { sig, err := os.ReadFile(filepath.Join(sigdir, f.Name())) if err != nil { diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go index c9e02eb68c..16b1260572 100644 --- a/cmd/utils/cmd.go +++ b/cmd/utils/cmd.go @@ -118,6 +118,9 @@ func StartNode(ctx *cli.Context, stack *node.Node, isConsole bool) { } func monitorFreeDiskSpace(sigc chan os.Signal, path string, freeDiskSpaceCritical uint64) { + if path == "" { + return + } for { freeSpace, err := getFreeDiskSpace(path) if err != nil { @@ -181,7 +184,7 @@ func ImportChain(chain *core.BlockChain, fn string) error { for batch := 0; ; batch++ { // Load a batch of RLP blocks. if checkInterrupt() { - return fmt.Errorf("interrupted") + return errors.New("interrupted") } i := 0 for ; i < importBatchSize; i++ { @@ -204,7 +207,7 @@ func ImportChain(chain *core.BlockChain, fn string) error { } // Import the batch. if checkInterrupt() { - return fmt.Errorf("interrupted") + return errors.New("interrupted") } missing := missingBlocks(chain, blocks[:i]) if len(missing) == 0 { diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index b67671e03b..f5f131951a 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -26,6 +26,7 @@ import ( "fmt" "math" "math/big" + "net" "net/http" "os" "path/filepath" @@ -41,13 +42,13 @@ import ( "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/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/crypto/kzg4844" "github.com/ethereum/go-ethereum/eth" - ethcatalyst "github.com/ethereum/go-ethereum/eth/catalyst" + "github.com/ethereum/go-ethereum/eth/catalyst" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/eth/filters" @@ -60,7 +61,6 @@ import ( "github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/les" - lescatalyst "github.com/ethereum/go-ethereum/les/catalyst" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/metrics/exp" @@ -74,6 +74,9 @@ import ( "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" + "github.com/ethereum/go-ethereum/trie" + "github.com/ethereum/go-ethereum/trie/triedb/hashdb" + "github.com/ethereum/go-ethereum/trie/triedb/pathdb" pcsclite "github.com/gballet/go-libpcsclite" gopsutil "github.com/shirou/gopsutil/mem" "github.com/urfave/cli/v2" @@ -133,7 +136,7 @@ var ( } NetworkIdFlag = &cli.Uint64Flag{ Name: "networkid", - Usage: "Explicitly set network id (integer)(For testnets: use --rinkeby, --goerli, --sepolia instead)", + Usage: "Explicitly set network id (integer)(For testnets: use --goerli, --sepolia, --holesky instead)", Value: ethconfig.Defaults.NetworkId, Category: flags.EthCategory, } @@ -142,11 +145,6 @@ var ( Usage: "Ethereum mainnet", Category: flags.EthCategory, } - RinkebyFlag = &cli.BoolFlag{ - Name: "rinkeby", - Usage: "Rinkeby network: pre-configured proof-of-authority test network", - Category: flags.EthCategory, - } GoerliFlag = &cli.BoolFlag{ Name: "goerli", Usage: "Görli network: pre-configured proof-of-authority test network", @@ -157,14 +155,18 @@ var ( Usage: "Sepolia network: pre-configured proof-of-work test network", Category: flags.EthCategory, } - + HoleskyFlag = &cli.BoolFlag{ + Name: "holesky", + Usage: "Holesky network: pre-configured proof-of-stake test network", + Category: flags.EthCategory, + } // Dev mode DeveloperFlag = &cli.BoolFlag{ Name: "dev", Usage: "Ephemeral proof-of-authority network with a pre-funded developer account, mining enabled", Category: flags.DevCategory, } - DeveloperPeriodFlag = &cli.IntFlag{ + DeveloperPeriodFlag = &cli.Uint64Flag{ Name: "dev.period", Usage: "Block period to use in developer mode (0 = mine only if transaction pending)", Category: flags.DevCategory, @@ -223,30 +225,12 @@ var ( } defaultSyncMode = ethconfig.Defaults.SyncMode - SyncModeFlag = &flags.TextMarshalerFlag{ - Name: "syncmode", - Usage: `Blockchain sync mode ("snap", "full" or "light")`, - Value: &defaultSyncMode, - Category: flags.EthCategory, - } - GCModeFlag = &cli.StringFlag{ - Name: "gcmode", - Usage: `Blockchain garbage collection mode ("full", "archive")`, - Value: "full", - Category: flags.EthCategory, - } - SnapshotFlag = &cli.BoolFlag{ + SnapshotFlag = &cli.BoolFlag{ Name: "snapshot", Usage: `Enables snapshot-database mode (default = enable)`, Value: true, Category: flags.EthCategory, } - TxLookupLimitFlag = &cli.Uint64Flag{ - Name: "txlookuplimit", - Usage: "Number of recent blocks to maintain transactions index for (default = about one year, 0 = entire chain)", - Value: ethconfig.Defaults.TxLookupLimit, - Category: flags.EthCategory, - } LightKDFFlag = &cli.BoolFlag{ Name: "lightkdf", Usage: "Reduce key-derivation RAM & CPU usage at some expense of KDF strength", @@ -257,11 +241,6 @@ var ( Usage: "Comma separated block number-to-hash mappings to require for peering (=)", Category: flags.EthCategory, } - LegacyWhitelistFlag = &cli.StringFlag{ - Name: "whitelist", - Usage: "Comma separated block number-to-hash mappings to enforce (=) (deprecated in favor of --eth.requiredblocks)", - Category: flags.DeprecatedCategory, - } BloomFilterSizeFlag = &cli.Uint64Flag{ Name: "bloomfilter.size", Usage: "Megabytes of memory allocated to bloom-filter for pruning", @@ -273,6 +252,41 @@ var ( Usage: "Manually specify the Cancun fork timestamp, overriding the bundled setting", Category: flags.EthCategory, } + OverrideVerkle = &cli.Uint64Flag{ + Name: "override.verkle", + Usage: "Manually specify the Verkle fork timestamp, overriding the bundled setting", + Category: flags.EthCategory, + } + SyncModeFlag = &flags.TextMarshalerFlag{ + Name: "syncmode", + Usage: `Blockchain sync mode ("snap", "full" or "light")`, + Value: &defaultSyncMode, + Category: flags.StateCategory, + } + GCModeFlag = &cli.StringFlag{ + Name: "gcmode", + Usage: `Blockchain garbage collection mode, only relevant in state.scheme=hash ("full", "archive")`, + Value: "full", + Category: flags.StateCategory, + } + StateSchemeFlag = &cli.StringFlag{ + Name: "state.scheme", + Usage: "Scheme to use for storing ethereum state ('hash' or 'path')", + Value: rawdb.HashScheme, + Category: flags.StateCategory, + } + StateHistoryFlag = &cli.Uint64Flag{ + Name: "history.state", + Usage: "Number of recent blocks to retain state history for (default = 90,000 blocks, 0 = entire chain)", + Value: ethconfig.Defaults.StateHistory, + Category: flags.StateCategory, + } + TransactionHistoryFlag = &cli.Uint64Flag{ + Name: "history.transactions", + Usage: "Number of recent blocks to maintain transactions index for (default = about one year, 0 = entire chain)", + Value: ethconfig.Defaults.TransactionHistory, + Category: flags.StateCategory, + } // Light server and client settings LightServeFlag = &cli.IntFlag{ Name: "light.serve", @@ -298,23 +312,6 @@ var ( Value: ethconfig.Defaults.LightPeers, Category: flags.LightCategory, } - UltraLightServersFlag = &cli.StringFlag{ - Name: "ulc.servers", - Usage: "List of trusted ultra-light servers", - Value: strings.Join(ethconfig.Defaults.UltraLightServers, ","), - Category: flags.LightCategory, - } - UltraLightFractionFlag = &cli.IntFlag{ - Name: "ulc.fraction", - Usage: "Minimum % of trusted ultra-light servers required to announce a new head", - Value: ethconfig.Defaults.UltraLightFraction, - Category: flags.LightCategory, - } - UltraLightOnlyAnnounceFlag = &cli.BoolFlag{ - Name: "ulc.onlyannounce", - Usage: "Ultra light server sends announcements only", - Category: flags.LightCategory, - } LightNoPruneFlag = &cli.BoolFlag{ Name: "light.nopruning", Usage: "Disable ancient light chain data pruning", @@ -339,18 +336,18 @@ var ( TxPoolJournalFlag = &cli.StringFlag{ Name: "txpool.journal", Usage: "Disk journal for local transaction to survive node restarts", - Value: txpool.DefaultConfig.Journal, + Value: ethconfig.Defaults.TxPool.Journal, Category: flags.TxPoolCategory, } TxPoolRejournalFlag = &cli.DurationFlag{ Name: "txpool.rejournal", Usage: "Time interval to regenerate the local transaction journal", - Value: txpool.DefaultConfig.Rejournal, + Value: ethconfig.Defaults.TxPool.Rejournal, Category: flags.TxPoolCategory, } TxPoolPriceLimitFlag = &cli.Uint64Flag{ Name: "txpool.pricelimit", - Usage: "Minimum gas price limit to enforce for acceptance into the pool", + Usage: "Minimum gas price tip to enforce for acceptance into the pool", Value: ethconfig.Defaults.TxPool.PriceLimit, Category: flags.TxPoolCategory, } @@ -390,7 +387,25 @@ var ( Value: ethconfig.Defaults.TxPool.Lifetime, Category: flags.TxPoolCategory, } - + // Blob transaction pool settings + BlobPoolDataDirFlag = &cli.StringFlag{ + Name: "blobpool.datadir", + Usage: "Data directory to store blob transactions in", + Value: ethconfig.Defaults.BlobPool.Datadir, + Category: flags.BlobPoolCategory, + } + BlobPoolDataCapFlag = &cli.Uint64Flag{ + Name: "blobpool.datacap", + Usage: "Disk space to allocate for pending blob transactions (soft limit)", + Value: ethconfig.Defaults.BlobPool.Datacap, + Category: flags.BlobPoolCategory, + } + BlobPoolPriceBumpFlag = &cli.Uint64Flag{ + Name: "blobpool.pricebump", + Usage: "Price bump percentage to replace an already existing blob transaction", + Value: ethconfig.Defaults.BlobPool.PriceBump, + Category: flags.BlobPoolCategory, + } // Performance tuning settings CacheFlag = &cli.IntFlag{ Name: "cache", @@ -410,18 +425,6 @@ var ( Value: 15, Category: flags.PerfCategory, } - CacheTrieJournalFlag = &cli.StringFlag{ - Name: "cache.trie.journal", - Usage: "Disk journal directory for trie cache to survive node restarts", - Value: ethconfig.Defaults.TrieCleanCacheJournal, - Category: flags.PerfCategory, - } - CacheTrieRejournalFlag = &cli.DurationFlag{ - Name: "cache.trie.rejournal", - Usage: "Time interval to regenerate the trie cache journal", - Value: ethconfig.Defaults.TrieCleanCacheRejournal, - Category: flags.PerfCategory, - } CacheGCFlag = &cli.IntFlag{ Name: "cache.gc", Usage: "Percentage of cache memory allowance to use for trie pruning (default = 25% full mode, 0% archive mode)", @@ -718,6 +721,18 @@ var ( Usage: "Allow for unprotected (non EIP155 signed) transactions to be submitted via RPC", Category: flags.APICategory, } + BatchRequestLimit = &cli.IntFlag{ + Name: "rpc.batch-request-limit", + Usage: "Maximum number of requests in a batch", + Value: node.DefaultConfig.BatchRequestLimit, + Category: flags.APICategory, + } + BatchResponseMaxSize = &cli.IntFlag{ + Name: "rpc.batch-response-max-size", + Usage: "Maximum number of bytes returned from a batched call", + Value: node.DefaultConfig.BatchResponseMaxSize, + Category: flags.APICategory, + } EnablePersonal = &cli.BoolFlag{ Name: "rpc.enabledeprecatedpersonal", Usage: "Enables the (deprecated) personal namespace", @@ -770,8 +785,16 @@ var ( Usage: "Disables the peer discovery mechanism (manual peer addition)", Category: flags.NetworkingCategory, } + DiscoveryV4Flag = &cli.BoolFlag{ + Name: "discovery.v4", + Aliases: []string{"discv4"}, + Usage: "Enables the V4 discovery mechanism", + Category: flags.NetworkingCategory, + Value: true, + } DiscoveryV5Flag = &cli.BoolFlag{ - Name: "v5disc", + Name: "discovery.v5", + Aliases: []string{"discv5"}, Usage: "Enables the experimental RLPx V5 (Topic Discovery) mechanism", Category: flags.NetworkingCategory, } @@ -931,9 +954,9 @@ 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{ - RinkebyFlag, GoerliFlag, SepoliaFlag, + HoleskyFlag, } // NetworkFlags is the flag group of all built-in supported networks. NetworkFlags = append([]cli.Flag{MainnetFlag}, TestnetFlags...) @@ -958,15 +981,15 @@ func init() { // 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(RinkebyFlag.Name) { - return filepath.Join(path, "rinkeby") - } if ctx.Bool(GoerliFlag.Name) { return filepath.Join(path, "goerli") } if ctx.Bool(SepoliaFlag.Name) { return filepath.Join(path, "sepolia") } + if ctx.Bool(HoleskyFlag.Name) { + return filepath.Join(path, "holesky") + } return path } Fatalf("Cannot determine default data directory, please set manually (--datadir)") @@ -1013,10 +1036,10 @@ func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) { switch { case ctx.IsSet(BootnodesFlag.Name): urls = SplitAndTrim(ctx.String(BootnodesFlag.Name)) + case ctx.Bool(HoleskyFlag.Name): + urls = params.HoleskyBootnodes case ctx.Bool(SepoliaFlag.Name): urls = params.SepoliaBootnodes - case ctx.Bool(RinkebyFlag.Name): - urls = params.RinkebyBootnodes case ctx.Bool(GoerliFlag.Name): urls = params.GoerliBootnodes } @@ -1141,6 +1164,14 @@ func setHTTP(ctx *cli.Context, cfg *node.Config) { if ctx.IsSet(AllowUnprotectedTxs.Name) { cfg.AllowUnprotectedTxs = ctx.Bool(AllowUnprotectedTxs.Name) } + + if ctx.IsSet(BatchRequestLimit.Name) { + cfg.BatchRequestLimit = ctx.Int(BatchRequestLimit.Name) + } + + if ctx.IsSet(BatchResponseMaxSize.Name) { + cfg.BatchResponseMaxSize = ctx.Int(BatchResponseMaxSize.Name) + } } // setGraphQL creates the GraphQL listener interface string from the set @@ -1206,19 +1237,6 @@ func setLes(ctx *cli.Context, cfg *ethconfig.Config) { if ctx.IsSet(LightMaxPeersFlag.Name) { cfg.LightPeers = ctx.Int(LightMaxPeersFlag.Name) } - if ctx.IsSet(UltraLightServersFlag.Name) { - cfg.UltraLightServers = strings.Split(ctx.String(UltraLightServersFlag.Name), ",") - } - if ctx.IsSet(UltraLightFractionFlag.Name) { - cfg.UltraLightFraction = ctx.Int(UltraLightFractionFlag.Name) - } - if cfg.UltraLightFraction <= 0 && cfg.UltraLightFraction > 100 { - log.Error("Ultra light fraction is invalid", "had", cfg.UltraLightFraction, "updated", ethconfig.Defaults.UltraLightFraction) - cfg.UltraLightFraction = ethconfig.Defaults.UltraLightFraction - } - if ctx.IsSet(UltraLightOnlyAnnounceFlag.Name) { - cfg.UltraLightOnlyAnnounce = ctx.Bool(UltraLightOnlyAnnounceFlag.Name) - } if ctx.IsSet(LightNoPruneFlag.Name) { cfg.LightNoPrune = ctx.Bool(LightNoPruneFlag.Name) } @@ -1359,13 +1377,17 @@ func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config) { cfg.NoDiscovery = true } - // if we're running a light client or server, force enable the v5 peer discovery - // unless it is explicitly disabled with --nodiscover note that explicitly specifying - // --v5disc overrides --nodiscover, in which case the later only disables v4 discovery - forceV5Discovery := (lightClient || lightServer) && !ctx.Bool(NoDiscoverFlag.Name) - if ctx.IsSet(DiscoveryV5Flag.Name) { - cfg.DiscoveryV5 = ctx.Bool(DiscoveryV5Flag.Name) - } else if forceV5Discovery { + // Disallow --nodiscover when used in conjunction with light mode. + if (lightClient || lightServer) && ctx.Bool(NoDiscoverFlag.Name) { + Fatalf("Cannot use --" + NoDiscoverFlag.Name + " in light client or light server mode") + } + CheckExclusive(ctx, DiscoveryV4Flag, NoDiscoverFlag) + CheckExclusive(ctx, DiscoveryV5Flag, NoDiscoverFlag) + cfg.DiscoveryV4 = ctx.Bool(DiscoveryV4Flag.Name) + cfg.DiscoveryV5 = ctx.Bool(DiscoveryV5Flag.Name) + + // If we're running a light client or server, force enable the v5 peer discovery. + if lightClient || lightServer { cfg.DiscoveryV5 = true } @@ -1464,12 +1486,12 @@ 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(RinkebyFlag.Name) && cfg.DataDir == node.DefaultDataDir(): - cfg.DataDir = filepath.Join(node.DefaultDataDir(), "rinkeby") 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(): + cfg.DataDir = filepath.Join(node.DefaultDataDir(), "holesky") } } @@ -1493,7 +1515,7 @@ func setGPO(ctx *cli.Context, cfg *gasprice.Config, light bool) { } } -func setTxPool(ctx *cli.Context, cfg *txpool.Config) { +func setTxPool(ctx *cli.Context, cfg *legacypool.Config) { if ctx.IsSet(TxPoolLocalsFlag.Name) { locals := strings.Split(ctx.String(TxPoolLocalsFlag.Name), ",") for _, account := range locals { @@ -1626,16 +1648,11 @@ 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, RinkebyFlag, GoerliFlag, SepoliaFlag) + CheckExclusive(ctx, MainnetFlag, DeveloperFlag, GoerliFlag, SepoliaFlag, HoleskyFlag) CheckExclusive(ctx, LightServeFlag, SyncModeFlag, "light") CheckExclusive(ctx, DeveloperFlag, ExternalSignerFlag) // Can't use both ephemeral unlocked and external signer - if ctx.String(GCModeFlag.Name) == "archive" && ctx.Uint64(TxLookupLimitFlag.Name) != 0 { - ctx.Set(TxLookupLimitFlag.Name, "0") - log.Warn("Disable transaction unindexing for archive node") - } - if ctx.IsSet(LightServeFlag.Name) && ctx.Uint64(TxLookupLimitFlag.Name) != 0 { - log.Warn("LES server cannot serve old transaction status and cannot connect below les/4 protocol version if transaction lookup index is limited") - } + + // Set configurations from CLI flags setEtherbase(ctx, cfg) setGPO(ctx, &cfg.GPO, ctx.String(SyncModeFlag.Name) == "light") setTxPool(ctx, &cfg.TxPool) @@ -1692,18 +1709,40 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { cfg.Preimages = true log.Info("Enabling recording of key preimages since archive mode is used") } - if ctx.IsSet(TxLookupLimitFlag.Name) { - cfg.TxLookupLimit = ctx.Uint64(TxLookupLimitFlag.Name) + if ctx.IsSet(StateHistoryFlag.Name) { + cfg.StateHistory = ctx.Uint64(StateHistoryFlag.Name) + } + // Parse state scheme, abort the process if it's not compatible. + chaindb := tryMakeReadOnlyDatabase(ctx, stack) + scheme, err := ParseStateScheme(ctx, chaindb) + chaindb.Close() + if err != nil { + Fatalf("%v", err) + } + cfg.StateScheme = scheme + + // Parse transaction history flag, if user is still using legacy config + // file with 'TxLookupLimit' configured, copy the value to 'TransactionHistory'. + if cfg.TransactionHistory == ethconfig.Defaults.TransactionHistory && cfg.TxLookupLimit != ethconfig.Defaults.TxLookupLimit { + log.Warn("The config option 'TxLookupLimit' is deprecated and will be removed, please use 'TransactionHistory'") + cfg.TransactionHistory = cfg.TxLookupLimit + } + if ctx.IsSet(TransactionHistoryFlag.Name) { + cfg.TransactionHistory = ctx.Uint64(TransactionHistoryFlag.Name) + } else if ctx.IsSet(TxLookupLimitFlag.Name) { + log.Warn("The flag --txlookuplimit is deprecated and will be removed, please use --history.transactions") + cfg.TransactionHistory = ctx.Uint64(TxLookupLimitFlag.Name) + } + if ctx.String(GCModeFlag.Name) == "archive" && cfg.TransactionHistory != 0 { + cfg.TransactionHistory = 0 + log.Warn("Disabled transaction unindexing for archive node") + } + if ctx.IsSet(LightServeFlag.Name) && cfg.TransactionHistory != 0 { + log.Warn("LES server cannot serve old transaction status and cannot connect below les/4 protocol version if transaction lookup index is limited") } if ctx.IsSet(CacheFlag.Name) || ctx.IsSet(CacheTrieFlag.Name) { cfg.TrieCleanCache = ctx.Int(CacheFlag.Name) * ctx.Int(CacheTrieFlag.Name) / 100 } - if ctx.IsSet(CacheTrieJournalFlag.Name) { - cfg.TrieCleanCacheJournal = ctx.String(CacheTrieJournalFlag.Name) - } - if ctx.IsSet(CacheTrieRejournalFlag.Name) { - cfg.TrieCleanCacheRejournal = ctx.Duration(CacheTrieRejournalFlag.Name) - } if ctx.IsSet(CacheFlag.Name) || ctx.IsSet(CacheGCFlag.Name) { cfg.TrieDirtyCache = ctx.Int(CacheFlag.Name) * ctx.Int(CacheGCFlag.Name) / 100 } @@ -1762,28 +1801,18 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { } cfg.Genesis = core.DefaultGenesisBlock() SetDNSDiscoveryDefaults(cfg, params.MainnetGenesisHash) + case ctx.Bool(HoleskyFlag.Name): + if !ctx.IsSet(NetworkIdFlag.Name) { + cfg.NetworkId = 17000 + } + cfg.Genesis = core.DefaultHoleskyGenesisBlock() + SetDNSDiscoveryDefaults(cfg, params.HoleskyGenesisHash) case ctx.Bool(SepoliaFlag.Name): if !ctx.IsSet(NetworkIdFlag.Name) { cfg.NetworkId = 11155111 } cfg.Genesis = core.DefaultSepoliaGenesisBlock() SetDNSDiscoveryDefaults(cfg, params.SepoliaGenesisHash) - case ctx.Bool(RinkebyFlag.Name): - log.Warn("") - log.Warn("--------------------------------------------------------------------------------") - log.Warn("Please note, Rinkeby has been deprecated. It will still work for the time being,") - log.Warn("but there will be no further hard-forks shipped for it.") - log.Warn("The network will be permanently halted in Q2/Q3 of 2023.") - log.Warn("For the most future proof testnet, choose Sepolia as") - log.Warn("your replacement environment (--sepolia instead of --rinkeby).") - log.Warn("--------------------------------------------------------------------------------") - log.Warn("") - - if !ctx.IsSet(NetworkIdFlag.Name) { - cfg.NetworkId = 4 - } - cfg.Genesis = core.DefaultRinkebyGenesisBlock() - SetDNSDiscoveryDefaults(cfg, params.RinkebyGenesisHash) case ctx.Bool(GoerliFlag.Name): if !ctx.IsSet(NetworkIdFlag.Name) { cfg.NetworkId = 5 @@ -1839,17 +1868,9 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { log.Info("Using developer account", "address", developer.Address) // Create a new developer genesis block or reuse existing one - cfg.Genesis = core.DeveloperGenesisBlock(uint64(ctx.Int(DeveloperPeriodFlag.Name)), ctx.Uint64(DeveloperGasLimitFlag.Name), developer.Address) + cfg.Genesis = core.DeveloperGenesisBlock(ctx.Uint64(DeveloperGasLimitFlag.Name), developer.Address) if ctx.IsSet(DataDirFlag.Name) { - // If datadir doesn't exist we need to open db in write-mode - // so leveldb can create files. - readonly := true - if !common.FileExist(stack.ResolvePath("chaindata")) { - readonly = false - } - // Check if we have an already initialized chain and fall back to - // that if so. Otherwise we need to generate a new genesis spec. - chaindb := MakeChainDatabase(ctx, stack, readonly) + chaindb := tryMakeReadOnlyDatabase(ctx, stack) if rawdb.ReadCanonicalHash(chaindb, 0) != (common.Hash{}) { cfg.Genesis = nil // fallback to db content } @@ -1899,9 +1920,6 @@ func RegisterEthService(stack *node.Node, cfg *ethconfig.Config) (ethapi.Backend Fatalf("Failed to register the Ethereum service: %v", err) } stack.RegisterAPIs(tracers.APIs(backend.ApiBackend)) - if err := lescatalyst.Register(stack, backend); err != nil { - Fatalf("Failed to register the Engine API service: %v", err) - } return backend.ApiBackend, nil } backend, err := eth.New(stack, cfg) @@ -1914,9 +1932,6 @@ func RegisterEthService(stack *node.Node, cfg *ethconfig.Config) (ethapi.Backend Fatalf("Failed to create the LES server: %v", err) } } - if err := ethcatalyst.Register(stack, backend); err != nil { - Fatalf("Failed to register the Engine API service: %v", err) - } stack.RegisterAPIs(tracers.APIs(backend.APIBackend)) return backend.APIBackend, backend } @@ -1963,7 +1978,7 @@ func RegisterFullSyncTester(stack *node.Node, eth *eth.Ethereum, path string) { if err := rlp.DecodeBytes(rlpBlob, &block); err != nil { Fatalf("Failed to decode block: %v", err) } - ethcatalyst.RegisterFullSyncTester(stack, eth, &block) + catalyst.RegisterFullSyncTester(stack, eth, &block) log.Info("Registered full-sync tester", "number", block.NumberU64(), "hash", block.Hash()) } @@ -2019,7 +2034,7 @@ func SetupMetrics(ctx *cli.Context) { } if ctx.IsSet(MetricsHTTPFlag.Name) { - address := fmt.Sprintf("%s:%d", ctx.String(MetricsHTTPFlag.Name), ctx.Int(MetricsPortFlag.Name)) + address := net.JoinHostPort(ctx.String(MetricsHTTPFlag.Name), fmt.Sprintf("%d", ctx.Int(MetricsPortFlag.Name))) log.Info("Enabling stand-alone metrics HTTP endpoint", "address", address) exp.Setup(address) } else if ctx.IsSet(MetricsPortFlag.Name) { @@ -2073,6 +2088,18 @@ func MakeChainDatabase(ctx *cli.Context, stack *node.Node, readonly bool) ethdb. return chainDb } +// tryMakeReadOnlyDatabase try to open the chain database in read-only mode, +// or fallback to write mode if the database is not initialized. +func tryMakeReadOnlyDatabase(ctx *cli.Context, stack *node.Node) ethdb.Database { + // If the database doesn't exist we need to open it in write-mode to allow + // the engine to create files. + readonly := true + if rawdb.PreexistingDatabase(stack.ResolvePath("chaindata")) == "" { + readonly = false + } + return MakeChainDatabase(ctx, stack, readonly) +} + func IsNetworkPreset(ctx *cli.Context) bool { for _, flag := range NetworkFlags { bFlag, _ := flag.(*cli.BoolFlag) @@ -2112,10 +2139,10 @@ func MakeGenesis(ctx *cli.Context) *core.Genesis { switch { case ctx.Bool(MainnetFlag.Name): genesis = core.DefaultGenesisBlock() + case ctx.Bool(HoleskyFlag.Name): + genesis = core.DefaultHoleskyGenesisBlock() case ctx.Bool(SepoliaFlag.Name): genesis = core.DefaultSepoliaGenesisBlock() - case ctx.Bool(RinkebyFlag.Name): - genesis = core.DefaultRinkebyGenesisBlock() case ctx.Bool(GoerliFlag.Name): genesis = core.DefaultGoerliGenesisBlock() case ctx.Bool(DeveloperFlag.Name): @@ -2141,6 +2168,10 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh if gcmode := ctx.String(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" { Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name) } + scheme, err := ParseStateScheme(ctx, chainDb) + if err != nil { + Fatalf("%v", err) + } cache := &core.CacheConfig{ TrieCleanLimit: ethconfig.Defaults.TrieCleanCache, TrieCleanNoPrefetch: ctx.Bool(CacheNoPrefetchFlag.Name), @@ -2149,6 +2180,8 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh TrieTimeLimit: ethconfig.Defaults.TrieTimeout, SnapshotLimit: ethconfig.Defaults.SnapshotCache, Preimages: ctx.Bool(CachePreimagesFlag.Name), + StateScheme: scheme, + StateHistory: ctx.Uint64(StateHistoryFlag.Name), } if cache.TrieDirtyDisabled && !cache.Preimages { cache.Preimages = true @@ -2193,3 +2226,62 @@ func MakeConsolePreloads(ctx *cli.Context) []string { } return preloads } + +// ParseStateScheme resolves scheme identifier from CLI flag. If the provided +// state scheme is not compatible with the one of persistent scheme, an error +// will be returned. +// +// - none: use the scheme consistent with persistent state, or fallback +// to hash-based scheme if state is empty. +// - hash: use hash-based scheme or error out if not compatible with +// persistent state scheme. +// - path: use path-based scheme or error out if not compatible with +// persistent state scheme. +func ParseStateScheme(ctx *cli.Context, disk ethdb.Database) (string, error) { + // If state scheme is not specified, use the scheme consistent + // with persistent state, or fallback to hash mode if database + // is empty. + stored := rawdb.ReadStateScheme(disk) + if !ctx.IsSet(StateSchemeFlag.Name) { + 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 rawdb.HashScheme, nil + } + 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 compatible with + // persistent state. + scheme := ctx.String(StateSchemeFlag.Name) + if stored == "" || scheme == stored { + log.Info("State scheme set by user", "scheme", scheme) + return scheme, nil + } + return "", fmt.Errorf("incompatible state scheme, stored: %s, provided: %s", stored, scheme) +} + +// MakeTrieDatabase constructs a trie database based on the configured scheme. +func MakeTrieDatabase(ctx *cli.Context, disk ethdb.Database, preimage bool, readOnly bool) *trie.Database { + config := &trie.Config{ + Preimages: preimage, + } + scheme, err := ParseStateScheme(ctx, disk) + if err != nil { + Fatalf("%v", err) + } + if scheme == rawdb.HashScheme { + // Read-only mode is not implemented in hash mode, + // ignore the parameter silently. TODO(rjl493456442) + // please config it if read mode is implemented. + config.HashDB = hashdb.Defaults + return trie.NewDatabase(disk, config) + } + if readOnly { + config.PathDB = pathdb.ReadOnly + } else { + config.PathDB = pathdb.Defaults + } + return trie.NewDatabase(disk, config) +} diff --git a/cmd/utils/flags_legacy.go b/cmd/utils/flags_legacy.go index 930b68fb91..6669ff176f 100644 --- a/cmd/utils/flags_legacy.go +++ b/cmd/utils/flags_legacy.go @@ -19,6 +19,7 @@ package utils import ( "fmt" + "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/internal/flags" "github.com/urfave/cli/v2" ) @@ -33,15 +34,49 @@ var ShowDeprecated = &cli.Command{ var DeprecatedFlags = []cli.Flag{ NoUSBFlag, + LegacyWhitelistFlag, + CacheTrieJournalFlag, + CacheTrieRejournalFlag, + LegacyDiscoveryV5Flag, + TxLookupLimitFlag, } var ( - // (Deprecated May 2020, shown in aliased flags section) + // Deprecated May 2020, shown in aliased flags section NoUSBFlag = &cli.BoolFlag{ Name: "nousb", Usage: "Disables monitoring for and managing USB hardware wallets (deprecated)", Category: flags.DeprecatedCategory, } + // Deprecated March 2022 + LegacyWhitelistFlag = &cli.StringFlag{ + Name: "whitelist", + Usage: "Comma separated block number-to-hash mappings to enforce (=) (deprecated in favor of --eth.requiredblocks)", + Category: flags.DeprecatedCategory, + } + // Deprecated July 2023 + CacheTrieJournalFlag = &cli.StringFlag{ + Name: "cache.trie.journal", + Usage: "Disk journal directory for trie cache to survive node restarts", + Category: flags.DeprecatedCategory, + } + CacheTrieRejournalFlag = &cli.DurationFlag{ + Name: "cache.trie.rejournal", + Usage: "Time interval to regenerate the trie cache journal", + Category: flags.DeprecatedCategory, + } + LegacyDiscoveryV5Flag = &cli.BoolFlag{ + Name: "v5disc", + Usage: "Enables the experimental RLPx V5 (Topic Discovery) mechanism (deprecated, use --discv5 instead)", + Category: flags.DeprecatedCategory, + } + // Deprecated August 2023 + TxLookupLimitFlag = &cli.Uint64Flag{ + Name: "txlookuplimit", + Usage: "Number of recent blocks to maintain transactions index for (default = about one year, 0 = entire chain) (deprecated, use history.transactions instead)", + Value: ethconfig.Defaults.TransactionHistory, + Category: flags.DeprecatedCategory, + } ) // showDeprecated displays deprecated flags that will be soon removed from the codebase. diff --git a/common/lru/basiclru_test.go b/common/lru/basiclru_test.go index e2d3559f55..29812bda15 100644 --- a/common/lru/basiclru_test.go +++ b/common/lru/basiclru_test.go @@ -170,6 +170,20 @@ func TestBasicLRUContains(t *testing.T) { } } +// Test that Peek doesn't update recent-ness +func TestBasicLRUPeek(t *testing.T) { + cache := NewBasicLRU[int, int](2) + cache.Add(1, 1) + cache.Add(2, 2) + if v, ok := cache.Peek(1); !ok || v != 1 { + t.Errorf("1 should be set to 1") + } + cache.Add(3, 3) + if cache.Contains(1) { + t.Errorf("should not have updated recent-ness of 1") + } +} + func BenchmarkLRU(b *testing.B) { var ( capacity = 1000 diff --git a/common/math/big.go b/common/math/big.go index 1c2afa749a..013c0ba4b6 100644 --- a/common/math/big.go +++ b/common/math/big.go @@ -82,7 +82,7 @@ func (i *HexOrDecimal256) MarshalText() ([]byte, error) { // it however accepts either "0x"-prefixed (hex encoded) or non-prefixed (decimal) type Decimal256 big.Int -// NewHexOrDecimal256 creates a new Decimal256 +// NewDecimal256 creates a new Decimal256 func NewDecimal256(x int64) *Decimal256 { b := big.NewInt(x) d := Decimal256(*b) diff --git a/common/types.go b/common/types.go index 0b68a19dd3..bf74e43716 100644 --- a/common/types.go +++ b/common/types.go @@ -26,6 +26,7 @@ import ( "math/big" "math/rand" "reflect" + "strconv" "strings" "github.com/ethereum/go-ethereum/common/hexutil" @@ -64,6 +65,11 @@ func BigToHash(b *big.Int) Hash { return BytesToHash(b.Bytes()) } // If b is larger than len(h), b will be cropped from the left. func HexToHash(s string) Hash { return BytesToHash(FromHex(s)) } +// Cmp compares two hashes. +func (h Hash) Cmp(other Hash) int { + return bytes.Compare(h[:], other[:]) +} + // Bytes gets the byte representation of the underlying hash. func (h Hash) Bytes() []byte { return h[:] } @@ -225,6 +231,11 @@ func IsHexAddress(s string) bool { return len(s) == 2*AddressLength && isHex(s) } +// Cmp compares two addresses. +func (a Address) Cmp(other Address) int { + return bytes.Compare(a[:], other[:]) +} + // Bytes gets the string representation of the underlying address. func (a Address) Bytes() []byte { return a[:] } @@ -429,3 +440,35 @@ func (ma *MixedcaseAddress) ValidChecksum() bool { func (ma *MixedcaseAddress) Original() string { return ma.original } + +// AddressEIP55 is an alias of Address with a customized json marshaller +type AddressEIP55 Address + +// String returns the hex representation of the address in the manner of EIP55. +func (addr AddressEIP55) String() string { + return Address(addr).Hex() +} + +// MarshalJSON marshals the address in the manner of EIP55. +func (addr AddressEIP55) MarshalJSON() ([]byte, error) { + return json.Marshal(addr.String()) +} + +type Decimal uint64 + +func isString(input []byte) bool { + return len(input) >= 2 && input[0] == '"' && input[len(input)-1] == '"' +} + +// UnmarshalJSON parses a hash in hex syntax. +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 { + *d = Decimal(i) + return nil + } else { + return err + } +} diff --git a/common/types_test.go b/common/types_test.go index 88c642522d..cec689ea39 100644 --- a/common/types_test.go +++ b/common/types_test.go @@ -25,6 +25,7 @@ import ( "reflect" "strings" "testing" + "time" ) func TestBytesConversion(t *testing.T) { @@ -559,3 +560,38 @@ func TestHash_Format(t *testing.T) { }) } } + +func TestAddressEIP55(t *testing.T) { + addr := HexToAddress("0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed") + addrEIP55 := AddressEIP55(addr) + + if addr.Hex() != addrEIP55.String() { + t.Fatal("AddressEIP55 should match original address hex") + } + + blob, err := addrEIP55.MarshalJSON() + if err != nil { + t.Fatal("Failed to marshal AddressEIP55", err) + } + if strings.Trim(string(blob), "\"") != addr.Hex() { + t.Fatal("Address with checksum is expected") + } + var dec Address + if err := json.Unmarshal(blob, &dec); err != nil { + t.Fatal("Failed to unmarshal AddressEIP55", err) + } + if addr != dec { + t.Fatal("Unexpected address after unmarshal") + } +} + +func BenchmarkPrettyDuration(b *testing.B) { + var x = PrettyDuration(time.Duration(int64(1203123912312))) + b.Logf("Pre %s", time.Duration(x).String()) + var a string + b.ResetTimer() + for i := 0; i < b.N; i++ { + a = x.String() + } + b.Logf("Post %s", a) +} diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index 284477b277..e856f4e6ce 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -23,7 +23,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" - "github.com/ethereum/go-ethereum/consensus/misc" + "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/types" "github.com/ethereum/go-ethereum/params" @@ -257,24 +258,35 @@ func (beacon *Beacon) verifyHeader(chain consensus.ChainHeaderReader, header, pa return consensus.ErrInvalidNumber } // Verify the header's EIP-1559 attributes. - if err := misc.VerifyEip1559Header(chain.Config(), parent, header); err != nil { + if err := eip1559.VerifyEIP1559Header(chain.Config(), parent, header); err != nil { return err } // Verify existence / non-existence of withdrawalsHash. - shanghai := chain.Config().IsShanghai(header.Time) + shanghai := chain.Config().IsShanghai(header.Number, header.Time) if shanghai && header.WithdrawalsHash == nil { return errors.New("missing withdrawalsHash") } if !shanghai && header.WithdrawalsHash != nil { return fmt.Errorf("invalid withdrawalsHash: have %x, expected nil", header.WithdrawalsHash) } - // Verify the existence / non-existence of excessDataGas - cancun := chain.Config().IsCancun(header.Time) - if cancun && header.ExcessDataGas == nil { - return errors.New("missing excessDataGas") - } - if !cancun && header.ExcessDataGas != nil { - return fmt.Errorf("invalid excessDataGas: have %d, expected nil", header.ExcessDataGas) + // Verify the existence / non-existence of cancun-specific header fields + cancun := chain.Config().IsCancun(header.Number, header.Time) + if !cancun { + switch { + case header.ExcessBlobGas != nil: + return fmt.Errorf("invalid excessBlobGas: have %d, expected nil", header.ExcessBlobGas) + case header.BlobGasUsed != nil: + return fmt.Errorf("invalid blobGasUsed: have %d, expected nil", header.BlobGasUsed) + case header.ParentBeaconRoot != nil: + return fmt.Errorf("invalid parentBeaconRoot, have %#x, expected nil", header.ParentBeaconRoot) + } + } else { + if header.ParentBeaconRoot == nil { + return errors.New("header is missing beaconRoot") + } + if err := eip4844.VerifyEIP4844Header(parent, header); err != nil { + return err + } } return nil } @@ -356,7 +368,7 @@ func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, hea if !beacon.IsPoSHeader(header) { return beacon.ethone.FinalizeAndAssemble(chain, header, state, txs, uncles, receipts, nil) } - shanghai := chain.Config().IsShanghai(header.Time) + shanghai := chain.Config().IsShanghai(header.Number, header.Time) if shanghai { // All blocks after Shanghai must include a withdrawals root. if withdrawals == nil { diff --git a/consensus/clique/api.go b/consensus/clique/api.go index cb270d321d..374b50692d 100644 --- a/consensus/clique/api.go +++ b/consensus/clique/api.go @@ -205,7 +205,7 @@ func (sb *blockNumberOrHashOrRLP) UnmarshalJSON(data []byte) error { } // GetSigner returns the signer for a specific clique block. -// Can be called with either a blocknumber, blockhash or an rlp encoded blob. +// Can be called with a block number, a block hash or a rlp encoded blob. // The RLP encoded blob can either be a block or a header. func (api *API) GetSigner(rlpOrBlockNr *blockNumberOrHashOrRLP) (common.Address, error) { if len(rlpOrBlockNr.RLP) == 0 { diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index 535cbeb262..f708050abd 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -33,6 +33,7 @@ import ( 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" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" @@ -298,11 +299,11 @@ func (c *Clique) verifyHeader(chain consensus.ChainHeaderReader, header *types.H if header.GasLimit > params.MaxGasLimit { return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, params.MaxGasLimit) } - if chain.Config().IsShanghai(header.Time) { - return fmt.Errorf("clique does not support shanghai fork") + if chain.Config().IsShanghai(header.Number, header.Time) { + return errors.New("clique does not support shanghai fork") } - if chain.Config().IsCancun(header.Time) { - return fmt.Errorf("clique does not support cancun fork") + if chain.Config().IsCancun(header.Number, header.Time) { + return errors.New("clique does not support cancun fork") } // All basic checks passed, verify cascading fields return c.verifyCascadingFields(chain, header, parents) @@ -343,7 +344,7 @@ func (c *Clique) verifyCascadingFields(chain consensus.ChainHeaderReader, header if err := misc.VerifyGaslimit(parent.GasLimit, header.GasLimit); err != nil { return err } - } else if err := misc.VerifyEip1559Header(chain.Config(), parent, header); err != nil { + } else if err := eip1559.VerifyEIP1559Header(chain.Config(), parent, header); err != nil { // Verify the header's EIP-1559 attributes. return err } diff --git a/consensus/clique/clique_test.go b/consensus/clique/clique_test.go index f2c6d740c0..7cd5919c5e 100644 --- a/consensus/clique/clique_test.go +++ b/consensus/clique/clique_test.go @@ -30,7 +30,7 @@ import ( ) // This test case is a repro of an annoying bug that took us forever to catch. -// In Clique PoA networks (Rinkeby, Görli, etc), consecutive blocks might have +// 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 diff --git a/consensus/clique/snapshot.go b/consensus/clique/snapshot.go index e5efa5108f..a97115121b 100644 --- a/consensus/clique/snapshot.go +++ b/consensus/clique/snapshot.go @@ -19,7 +19,6 @@ package clique import ( "bytes" "encoding/json" - "sort" "time" "github.com/ethereum/go-ethereum/common" @@ -29,6 +28,7 @@ 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 @@ -62,13 +62,6 @@ type Snapshot struct { Tally map[common.Address]Tally `json:"tally"` // Current vote tally to avoid recalculating } -// signersAscending implements the sort interface to allow sorting a list of addresses -type signersAscending []common.Address - -func (s signersAscending) Len() int { return len(s) } -func (s signersAscending) Less(i, j int) bool { return bytes.Compare(s[i][:], s[j][:]) < 0 } -func (s signersAscending) Swap(i, j int) { s[i], s[j] = s[j], s[i] } - // newSnapshot creates a new snapshot with the specified startup parameters. This // method does not initialize the set of recent signers, so only ever use if for // the genesis block. @@ -315,7 +308,7 @@ func (s *Snapshot) signers() []common.Address { for sig := range s.Signers { sigs = append(sigs, sig) } - sort.Sort(signersAscending(sigs)) + slices.SortFunc(sigs, common.Address.Cmp) return sigs } diff --git a/consensus/clique/snapshot_test.go b/consensus/clique/snapshot_test.go index 66e667276f..26cebe008a 100644 --- a/consensus/clique/snapshot_test.go +++ b/consensus/clique/snapshot_test.go @@ -21,7 +21,6 @@ import ( "crypto/ecdsa" "fmt" "math/big" - "sort" "testing" "github.com/ethereum/go-ethereum/common" @@ -31,6 +30,7 @@ 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, @@ -53,7 +53,7 @@ func (ap *testerAccountPool) checkpoint(header *types.Header, signers []string) for i, signer := range signers { auths[i] = ap.address(signer) } - sort.Sort(signersAscending(auths)) + slices.SortFunc(auths, common.Address.Cmp) for i, auth := range auths { copy(header.Extra[extraVanity+i*common.AddressLength:], auth.Bytes()) } diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index b912fb513a..8eb9863da1 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -27,6 +27,7 @@ import ( "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/consensus" "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/types" "github.com/ethereum/go-ethereum/params" @@ -254,7 +255,7 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainHeaderReader, header, pa if err := misc.VerifyGaslimit(parent.GasLimit, header.GasLimit); err != nil { return err } - } else if err := misc.VerifyEip1559Header(chain.Config(), parent, header); err != nil { + } else if err := eip1559.VerifyEIP1559Header(chain.Config(), parent, header); err != nil { // Verify the header's EIP-1559 attributes. return err } @@ -262,11 +263,11 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainHeaderReader, header, pa if diff := new(big.Int).Sub(header.Number, parent.Number); diff.Cmp(big.NewInt(1)) != 0 { return consensus.ErrInvalidNumber } - if chain.Config().IsShanghai(header.Time) { - return fmt.Errorf("ethash does not support shanghai fork") + if chain.Config().IsShanghai(header.Number, header.Time) { + return errors.New("ethash does not support shanghai fork") } - if chain.Config().IsCancun(header.Time) { - return fmt.Errorf("ethash does not support cancun fork") + if chain.Config().IsCancun(header.Number, header.Time) { + return errors.New("ethash does not support cancun fork") } // Add some fake checks for tests if ethash.fakeDelay != nil { diff --git a/consensus/misc/eip1559.go b/consensus/misc/eip1559/eip1559.go similarity index 90% rename from consensus/misc/eip1559.go rename to consensus/misc/eip1559/eip1559.go index 4521b47b36..84b82c4c49 100644 --- a/consensus/misc/eip1559.go +++ b/consensus/misc/eip1559/eip1559.go @@ -14,33 +14,35 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package misc +package eip1559 import ( + "errors" "fmt" "math/big" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" ) -// VerifyEip1559Header verifies some header attributes which were changed in EIP-1559, +// VerifyEIP1559Header verifies some header attributes which were changed in EIP-1559, // - gas limit check // - basefee check -func VerifyEip1559Header(config *params.ChainConfig, parent, header *types.Header) error { +func VerifyEIP1559Header(config *params.ChainConfig, parent, header *types.Header) error { // Verify that the gas limit remains within allowed bounds parentGasLimit := parent.GasLimit if !config.IsLondon(parent.Number) { parentGasLimit = parent.GasLimit * config.ElasticityMultiplier() } - if err := VerifyGaslimit(parentGasLimit, header.GasLimit); err != nil { + if err := misc.VerifyGaslimit(parentGasLimit, header.GasLimit); err != nil { return err } // Verify the header is not malformed if header.BaseFee == nil { - return fmt.Errorf("header is missing baseFee") + return errors.New("header is missing baseFee") } // Verify the baseFee is correct based on the parent header. expectedBaseFee := CalcBaseFee(config, parent) diff --git a/consensus/misc/eip1559_test.go b/consensus/misc/eip1559/eip1559_test.go similarity index 98% rename from consensus/misc/eip1559_test.go rename to consensus/misc/eip1559/eip1559_test.go index 1a9f96bc43..b5afdf0fe5 100644 --- a/consensus/misc/eip1559_test.go +++ b/consensus/misc/eip1559/eip1559_test.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 misc +package eip1559 import ( "math/big" @@ -95,7 +95,7 @@ func TestBlockGasLimits(t *testing.T) { BaseFee: initial, Number: big.NewInt(tc.pNum + 1), } - err := VerifyEip1559Header(config(), parent, header) + err := VerifyEIP1559Header(config(), parent, header) if tc.ok && err != nil { t.Errorf("test %d: Expected valid header: %s", i, err) } diff --git a/consensus/misc/eip4844.go b/consensus/misc/eip4844.go deleted file mode 100644 index 66ca9bd26d..0000000000 --- a/consensus/misc/eip4844.go +++ /dev/null @@ -1,54 +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 misc - -import ( - "math/big" - - "github.com/ethereum/go-ethereum/params" -) - -var ( - minDataGasPrice = big.NewInt(params.BlobTxMinDataGasprice) - dataGaspriceUpdateFraction = big.NewInt(params.BlobTxDataGaspriceUpdateFraction) -) - -// CalcBlobFee calculates the blobfee from the header's excess data gas field. -func CalcBlobFee(excessDataGas *big.Int) *big.Int { - // If this block does not yet have EIP-4844 enabled, return the starting fee - if excessDataGas == nil { - return big.NewInt(params.BlobTxMinDataGasprice) - } - return fakeExponential(minDataGasPrice, excessDataGas, dataGaspriceUpdateFraction) -} - -// fakeExponential approximates factor * e ** (numerator / denominator) using -// Taylor expansion. -func fakeExponential(factor, numerator, denominator *big.Int) *big.Int { - var ( - output = new(big.Int) - accum = new(big.Int).Mul(factor, denominator) - ) - for i := 1; accum.Sign() > 0; i++ { - output.Add(output, accum) - - accum.Mul(accum, numerator) - accum.Div(accum, denominator) - accum.Div(accum, big.NewInt(int64(i))) - } - return output.Div(output, denominator) -} diff --git a/consensus/misc/eip4844/eip4844.go b/consensus/misc/eip4844/eip4844.go new file mode 100644 index 0000000000..2dad9a0cd3 --- /dev/null +++ b/consensus/misc/eip4844/eip4844.go @@ -0,0 +1,98 @@ +// 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 eip4844 + +import ( + "errors" + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/params" +) + +var ( + minBlobGasPrice = big.NewInt(params.BlobTxMinBlobGasprice) + blobGaspriceUpdateFraction = big.NewInt(params.BlobTxBlobGaspriceUpdateFraction) +) + +// VerifyEIP4844Header verifies the presence of the excessBlobGas field and that +// if the current block contains no transactions, the excessBlobGas is updated +// accordingly. +func VerifyEIP4844Header(parent, header *types.Header) error { + // Verify the header is not malformed + if header.ExcessBlobGas == nil { + return errors.New("header is missing excessBlobGas") + } + if header.BlobGasUsed == nil { + return errors.New("header is missing blobGasUsed") + } + // Verify that the blob gas used remains within reasonable limits. + if *header.BlobGasUsed > params.MaxBlobGasPerBlock { + return fmt.Errorf("blob gas used %d exceeds maximum allowance %d", *header.BlobGasUsed, params.MaxBlobGasPerBlock) + } + if *header.BlobGasUsed%params.BlobTxBlobGasPerBlob != 0 { + return fmt.Errorf("blob gas used %d not a multiple of blob gas per blob %d", header.BlobGasUsed, params.BlobTxBlobGasPerBlob) + } + // Verify the excessBlobGas is correct based on the parent header + var ( + parentExcessBlobGas uint64 + parentBlobGasUsed uint64 + ) + if parent.ExcessBlobGas != nil { + parentExcessBlobGas = *parent.ExcessBlobGas + parentBlobGasUsed = *parent.BlobGasUsed + } + expectedExcessBlobGas := CalcExcessBlobGas(parentExcessBlobGas, parentBlobGasUsed) + if *header.ExcessBlobGas != expectedExcessBlobGas { + return fmt.Errorf("invalid excessBlobGas: have %d, want %d, parent excessBlobGas %d, parent blobDataUsed %d", + *header.ExcessBlobGas, expectedExcessBlobGas, parentExcessBlobGas, parentBlobGasUsed) + } + return nil +} + +// CalcExcessBlobGas calculates the excess blob gas after applying the set of +// blobs on top of the excess blob gas. +func CalcExcessBlobGas(parentExcessBlobGas uint64, parentBlobGasUsed uint64) uint64 { + excessBlobGas := parentExcessBlobGas + parentBlobGasUsed + if excessBlobGas < params.BlobTxTargetBlobGasPerBlock { + return 0 + } + return excessBlobGas - params.BlobTxTargetBlobGasPerBlock +} + +// CalcBlobFee calculates the blobfee from the header's excess blob gas field. +func CalcBlobFee(excessBlobGas uint64) *big.Int { + return fakeExponential(minBlobGasPrice, new(big.Int).SetUint64(excessBlobGas), blobGaspriceUpdateFraction) +} + +// fakeExponential approximates factor * e ** (numerator / denominator) using +// Taylor expansion. +func fakeExponential(factor, numerator, denominator *big.Int) *big.Int { + var ( + output = new(big.Int) + accum = new(big.Int).Mul(factor, denominator) + ) + for i := 1; accum.Sign() > 0; i++ { + output.Add(output, accum) + + accum.Mul(accum, numerator) + accum.Div(accum, denominator) + accum.Div(accum, big.NewInt(int64(i))) + } + return output.Div(output, denominator) +} diff --git a/consensus/misc/eip4844_test.go b/consensus/misc/eip4844/eip4844_test.go similarity index 55% rename from consensus/misc/eip4844_test.go rename to consensus/misc/eip4844/eip4844_test.go index 5838cab8e6..ec417380fc 100644 --- a/consensus/misc/eip4844_test.go +++ b/consensus/misc/eip4844/eip4844_test.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 misc +package eip4844 import ( "fmt" @@ -24,22 +24,51 @@ import ( "github.com/ethereum/go-ethereum/params" ) +func TestCalcExcessBlobGas(t *testing.T) { + var tests = []struct { + excess uint64 + blobs uint64 + want uint64 + }{ + // The excess blob gas should not increase from zero if the used blob + // slots are below - or equal - to the target. + {0, 0, 0}, + {0, 1, 0}, + {0, params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob, 0}, + + // If the target blob gas is exceeded, the excessBlobGas should increase + // by however much it was overshot + {0, (params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob) + 1, params.BlobTxBlobGasPerBlob}, + {1, (params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob) + 1, params.BlobTxBlobGasPerBlob + 1}, + {1, (params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob) + 2, 2*params.BlobTxBlobGasPerBlob + 1}, + + // The excess blob gas should decrease by however much the target was + // under-shot, capped at zero. + {params.BlobTxTargetBlobGasPerBlock, params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob, params.BlobTxTargetBlobGasPerBlock}, + {params.BlobTxTargetBlobGasPerBlock, (params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob) - 1, params.BlobTxTargetBlobGasPerBlock - params.BlobTxBlobGasPerBlob}, + {params.BlobTxTargetBlobGasPerBlock, (params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob) - 2, params.BlobTxTargetBlobGasPerBlock - (2 * params.BlobTxBlobGasPerBlob)}, + {params.BlobTxBlobGasPerBlob - 1, (params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob) - 1, 0}, + } + for i, tt := range tests { + result := CalcExcessBlobGas(tt.excess, tt.blobs*params.BlobTxBlobGasPerBlob) + if result != tt.want { + t.Errorf("test %d: excess blob gas mismatch: have %v, want %v", i, result, tt.want) + } + } +} + func TestCalcBlobFee(t *testing.T) { tests := []struct { - excessDataGas int64 + excessBlobGas uint64 blobfee int64 }{ {0, 1}, - {1542706, 1}, - {1542707, 2}, - {10 * 1024 * 1024, 111}, - } - have := CalcBlobFee(nil) - if have.Int64() != params.BlobTxMinDataGasprice { - t.Errorf("nil test: blobfee mismatch: have %v, want %v", have, params.BlobTxMinDataGasprice) + {2314057, 1}, + {2314058, 2}, + {10 * 1024 * 1024, 23}, } for i, tt := range tests { - have := CalcBlobFee(big.NewInt(tt.excessDataGas)) + have := CalcBlobFee(tt.excessBlobGas) if have.Int64() != tt.blobfee { t.Errorf("test %d: blobfee mismatch: have %v want %v", i, have, tt.blobfee) } diff --git a/consensus/misc/gaslimit.go b/consensus/misc/gaslimit.go index 25f35300b9..dfcabd9a80 100644 --- a/consensus/misc/gaslimit.go +++ b/consensus/misc/gaslimit.go @@ -17,7 +17,6 @@ package misc import ( - "errors" "fmt" "github.com/ethereum/go-ethereum/params" @@ -36,7 +35,7 @@ func VerifyGaslimit(parentGasLimit, headerGasLimit uint64) error { return fmt.Errorf("invalid gas limit: have %d, want %d +-= %d", headerGasLimit, parentGasLimit, limit-1) } if headerGasLimit < params.MinGasLimit { - return errors.New("invalid gas limit below 5000") + return fmt.Errorf("invalid gas limit below %d", params.MinGasLimit) } return nil } diff --git a/console/bridge.go b/console/bridge.go index 21ef0e8e7b..c67686d6c3 100644 --- a/console/bridge.go +++ b/console/bridge.go @@ -18,6 +18,7 @@ package console import ( "encoding/json" + "errors" "fmt" "io" "reflect" @@ -77,18 +78,18 @@ func (b *bridge) NewAccount(call jsre.Call) (goja.Value, error) { return nil, err } if password != confirm { - return nil, fmt.Errorf("passwords don't match!") + return nil, errors.New("passwords don't match!") } // A single string password was specified, use that case len(call.Arguments) == 1 && call.Argument(0).ToString() != nil: password = call.Argument(0).ToString().String() default: - return nil, fmt.Errorf("expected 0 or 1 string argument") + return nil, errors.New("expected 0 or 1 string argument") } // Password acquired, execute the call and return newAccount, callable := goja.AssertFunction(getJeth(call.VM).Get("newAccount")) if !callable { - return nil, fmt.Errorf("jeth.newAccount is not callable") + return nil, errors.New("jeth.newAccount is not callable") } ret, err := newAccount(goja.Null(), call.VM.ToValue(password)) if err != nil { @@ -102,7 +103,7 @@ func (b *bridge) NewAccount(call jsre.Call) (goja.Value, error) { func (b *bridge) OpenWallet(call jsre.Call) (goja.Value, error) { // Make sure we have a wallet specified to open if call.Argument(0).ToObject(call.VM).ClassName() != "String" { - return nil, fmt.Errorf("first argument must be the wallet URL to open") + return nil, errors.New("first argument must be the wallet URL to open") } wallet := call.Argument(0) @@ -115,7 +116,7 @@ func (b *bridge) OpenWallet(call jsre.Call) (goja.Value, error) { // Open the wallet and return if successful in itself openWallet, callable := goja.AssertFunction(getJeth(call.VM).Get("openWallet")) if !callable { - return nil, fmt.Errorf("jeth.openWallet is not callable") + return nil, errors.New("jeth.openWallet is not callable") } val, err := openWallet(goja.Null(), wallet, passwd) if err == nil { @@ -198,7 +199,7 @@ func (b *bridge) readPassphraseAndReopenWallet(call jsre.Call) (goja.Value, erro } openWallet, callable := goja.AssertFunction(getJeth(call.VM).Get("openWallet")) if !callable { - return nil, fmt.Errorf("jeth.openWallet is not callable") + return nil, errors.New("jeth.openWallet is not callable") } return openWallet(goja.Null(), wallet, call.VM.ToValue(input)) } @@ -219,7 +220,7 @@ func (b *bridge) readPinAndReopenWallet(call jsre.Call) (goja.Value, error) { } openWallet, callable := goja.AssertFunction(getJeth(call.VM).Get("openWallet")) if !callable { - return nil, fmt.Errorf("jeth.openWallet is not callable") + return nil, errors.New("jeth.openWallet is not callable") } return openWallet(goja.Null(), wallet, call.VM.ToValue(input)) } @@ -230,13 +231,13 @@ func (b *bridge) readPinAndReopenWallet(call jsre.Call) (goja.Value, error) { // the RPC call. func (b *bridge) UnlockAccount(call jsre.Call) (goja.Value, error) { if len(call.Arguments) < 1 { - return nil, fmt.Errorf("usage: unlockAccount(account, [ password, duration ])") + return nil, errors.New("usage: unlockAccount(account, [ password, duration ])") } account := call.Argument(0) // Make sure we have an account specified to unlock. if goja.IsUndefined(account) || goja.IsNull(account) || account.ExportType().Kind() != reflect.String { - return nil, fmt.Errorf("first argument must be the account to unlock") + return nil, errors.New("first argument must be the account to unlock") } // If password is not given or is the null value, prompt the user for it. @@ -250,7 +251,7 @@ func (b *bridge) UnlockAccount(call jsre.Call) (goja.Value, error) { passwd = call.VM.ToValue(input) } else { if call.Argument(1).ExportType().Kind() != reflect.String { - return nil, fmt.Errorf("password must be a string") + return nil, errors.New("password must be a string") } passwd = call.Argument(1) } @@ -259,7 +260,7 @@ func (b *bridge) UnlockAccount(call jsre.Call) (goja.Value, error) { duration := goja.Null() if !goja.IsUndefined(call.Argument(2)) && !goja.IsNull(call.Argument(2)) { if !isNumber(call.Argument(2)) { - return nil, fmt.Errorf("unlock duration must be a number") + return nil, errors.New("unlock duration must be a number") } duration = call.Argument(2) } @@ -267,7 +268,7 @@ func (b *bridge) UnlockAccount(call jsre.Call) (goja.Value, error) { // Send the request to the backend and return. unlockAccount, callable := goja.AssertFunction(getJeth(call.VM).Get("unlockAccount")) if !callable { - return nil, fmt.Errorf("jeth.unlockAccount is not callable") + return nil, errors.New("jeth.unlockAccount is not callable") } return unlockAccount(goja.Null(), account, passwd, duration) } @@ -277,7 +278,7 @@ func (b *bridge) UnlockAccount(call jsre.Call) (goja.Value, error) { // jeth.sign) with it to actually execute the RPC call. func (b *bridge) Sign(call jsre.Call) (goja.Value, error) { if nArgs := len(call.Arguments); nArgs < 2 { - return nil, fmt.Errorf("usage: sign(message, account, [ password ])") + return nil, errors.New("usage: sign(message, account, [ password ])") } var ( message = call.Argument(0) @@ -286,10 +287,10 @@ func (b *bridge) Sign(call jsre.Call) (goja.Value, error) { ) if goja.IsUndefined(message) || message.ExportType().Kind() != reflect.String { - return nil, fmt.Errorf("first argument must be the message to sign") + return nil, errors.New("first argument must be the message to sign") } if goja.IsUndefined(account) || account.ExportType().Kind() != reflect.String { - return nil, fmt.Errorf("second argument must be the account to sign with") + return nil, errors.New("second argument must be the account to sign with") } // if the password is not given or null ask the user and ensure password is a string @@ -301,13 +302,13 @@ func (b *bridge) Sign(call jsre.Call) (goja.Value, error) { } passwd = call.VM.ToValue(input) } else if passwd.ExportType().Kind() != reflect.String { - return nil, fmt.Errorf("third argument must be the password to unlock the account") + return nil, errors.New("third argument must be the password to unlock the account") } // Send the request to the backend and return sign, callable := goja.AssertFunction(getJeth(call.VM).Get("sign")) if !callable { - return nil, fmt.Errorf("jeth.sign is not callable") + return nil, errors.New("jeth.sign is not callable") } return sign(goja.Null(), message, account, passwd) } @@ -315,11 +316,11 @@ func (b *bridge) Sign(call jsre.Call) (goja.Value, error) { // Sleep will block the console for the specified number of seconds. func (b *bridge) Sleep(call jsre.Call) (goja.Value, error) { if nArgs := len(call.Arguments); nArgs < 1 { - return nil, fmt.Errorf("usage: sleep()") + return nil, errors.New("usage: sleep()") } sleepObj := call.Argument(0) if goja.IsUndefined(sleepObj) || goja.IsNull(sleepObj) || !isNumber(sleepObj) { - return nil, fmt.Errorf("usage: sleep()") + return nil, errors.New("usage: sleep()") } sleep := sleepObj.ToFloat() time.Sleep(time.Duration(sleep * float64(time.Second))) @@ -336,17 +337,17 @@ func (b *bridge) SleepBlocks(call jsre.Call) (goja.Value, error) { ) nArgs := len(call.Arguments) if nArgs == 0 { - return nil, fmt.Errorf("usage: sleepBlocks([, max sleep in seconds])") + return nil, errors.New("usage: sleepBlocks([, max sleep in seconds])") } if nArgs >= 1 { if goja.IsNull(call.Argument(0)) || goja.IsUndefined(call.Argument(0)) || !isNumber(call.Argument(0)) { - return nil, fmt.Errorf("expected number as first argument") + return nil, errors.New("expected number as first argument") } blocks = call.Argument(0).ToInteger() } if nArgs >= 2 { if goja.IsNull(call.Argument(1)) || goja.IsUndefined(call.Argument(1)) || !isNumber(call.Argument(1)) { - return nil, fmt.Errorf("expected number as second argument") + return nil, errors.New("expected number as second argument") } sleep = call.Argument(1).ToInteger() } @@ -421,7 +422,7 @@ func (b *bridge) Send(call jsre.Call) (goja.Value, error) { JSON := call.VM.Get("JSON").ToObject(call.VM) parse, callable := goja.AssertFunction(JSON.Get("parse")) if !callable { - return nil, fmt.Errorf("JSON.parse is not a function") + return nil, errors.New("JSON.parse is not a function") } resultVal, err := parse(goja.Null(), call.VM.ToValue(string(result))) if err != nil { diff --git a/console/console_test.go b/console/console_test.go index cc61f021ce..ee5c36be4a 100644 --- a/console/console_test.go +++ b/console/console_test.go @@ -94,7 +94,7 @@ func newTester(t *testing.T, confOverride func(*ethconfig.Config)) *tester { t.Fatalf("failed to create node: %v", err) } ethConf := ðconfig.Config{ - Genesis: core.DeveloperGenesisBlock(15, 11_500_000, common.Address{}), + Genesis: core.DeveloperGenesisBlock(11_500_000, common.Address{}), Miner: miner.Config{ Etherbase: common.HexToAddress(testAddress), }, @@ -110,10 +110,11 @@ func newTester(t *testing.T, confOverride func(*ethconfig.Config)) *tester { if err = stack.Start(); err != nil { t.Fatalf("failed to start test stack: %v", err) } - client, err := stack.Attach() - if err != nil { - t.Fatalf("failed to attach to node: %v", err) - } + client := stack.Attach() + t.Cleanup(func() { + client.Close() + }) + prompter := &hookedPrompter{scheduler: make(chan string)} printer := new(bytes.Buffer) diff --git a/core/block_validator.go b/core/block_validator.go index bcb228830d..f3d65cea25 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -17,6 +17,7 @@ package core import ( + "errors" "fmt" "github.com/ethereum/go-ethereum/consensus" @@ -67,20 +68,48 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error { if hash := types.DeriveSha(block.Transactions(), trie.NewStackTrie(nil)); hash != header.TxHash { return fmt.Errorf("transaction root hash mismatch (header value %x, calculated %x)", header.TxHash, hash) } + // Withdrawals are present after the Shanghai fork. if header.WithdrawalsHash != nil { // Withdrawals list must be present in body after Shanghai. if block.Withdrawals() == nil { - return fmt.Errorf("missing withdrawals in block body") + return errors.New("missing withdrawals in block body") } if hash := types.DeriveSha(block.Withdrawals(), trie.NewStackTrie(nil)); hash != *header.WithdrawalsHash { return fmt.Errorf("withdrawals root hash mismatch (header value %x, calculated %x)", *header.WithdrawalsHash, hash) } } else if block.Withdrawals() != nil { - // Withdrawals are not allowed prior to shanghai fork - return fmt.Errorf("withdrawals present in block body") + // Withdrawals are not allowed prior to Shanghai fork + return errors.New("withdrawals present in block body") } + // Blob transactions may be present after the Cancun fork. + var blobs int + for i, tx := range block.Transactions() { + // Count the number of blobs to validate against the header's blobGasUsed + blobs += len(tx.BlobHashes()) + + // If the tx is a blob tx, it must NOT have a sidecar attached to be valid in a block. + if tx.BlobTxSidecar() != nil { + return fmt.Errorf("unexpected blob sidecar in transaction at index %d", i) + } + + // The individual checks for blob validity (version-check + not empty) + // happens in StateTransition. + } + + // Check blob gas usage. + if header.BlobGasUsed != nil { + if want := *header.BlobGasUsed / params.BlobTxBlobGasPerBlob; uint64(blobs) != want { // div because the header is surely good vs the body might be bloated + return fmt.Errorf("blob gas used mismatch (header %v, calculated %v)", *header.BlobGasUsed, blobs*params.BlobTxBlobGasPerBlob) + } + } else { + if blobs > 0 { + return errors.New("data blobs present in block body") + } + } + + // Ancestor block must be known. if !v.bc.HasBlockAndState(block.ParentHash(), block.NumberU64()-1) { if !v.bc.HasBlock(block.ParentHash(), block.NumberU64()-1) { return consensus.ErrUnknownAncestor diff --git a/core/block_validator_test.go b/core/block_validator_test.go index d189545166..48bdceff62 100644 --- a/core/block_validator_test.go +++ b/core/block_validator_test.go @@ -18,7 +18,6 @@ package core import ( "math/big" - "runtime" "testing" "time" @@ -36,6 +35,11 @@ import ( // Tests that simple header verification works, for both good and bad blocks. func TestHeaderVerification(t *testing.T) { + testHeaderVerification(t, rawdb.HashScheme) + testHeaderVerification(t, rawdb.PathScheme) +} + +func testHeaderVerification(t *testing.T, scheme string) { // Create a simple chain to verify var ( gspec = &Genesis{Config: params.TestChainConfig} @@ -46,7 +50,7 @@ func TestHeaderVerification(t *testing.T) { headers[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, ethash.NewFaker(), vm.Config{}, nil, nil) + chain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer chain.Stop() for i := 0; i < len(blocks); i++ { @@ -235,118 +239,6 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) { } } -// Tests that concurrent header verification works, for both good and bad blocks. -func TestHeaderConcurrentVerification2(t *testing.T) { testHeaderConcurrentVerification(t, 2) } -func TestHeaderConcurrentVerification8(t *testing.T) { testHeaderConcurrentVerification(t, 8) } -func TestHeaderConcurrentVerification32(t *testing.T) { testHeaderConcurrentVerification(t, 32) } - -func testHeaderConcurrentVerification(t *testing.T, threads int) { - // Create a simple chain to verify - var ( - gspec = &Genesis{Config: params.TestChainConfig} - _, blocks, _ = GenerateChainWithGenesis(gspec, ethash.NewFaker(), 8, nil) - ) - headers := make([]*types.Header, len(blocks)) - for i, block := range blocks { - headers[i] = block.Header() - } - // Set the number of threads to verify on - old := runtime.GOMAXPROCS(threads) - defer runtime.GOMAXPROCS(old) - - // Run the header checker for the entire block chain at once both for a valid and - // also an invalid chain (enough if one arbitrary block is invalid). - for i, valid := range []bool{true, false} { - var results <-chan error - - if valid { - chain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) - _, results = chain.engine.VerifyHeaders(chain, headers) - chain.Stop() - } else { - chain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, ethash.NewFakeFailer(uint64(len(headers)-1)), vm.Config{}, nil, nil) - _, results = chain.engine.VerifyHeaders(chain, headers) - chain.Stop() - } - // Wait for all the verification results - checks := make(map[int]error) - for j := 0; j < len(blocks); j++ { - select { - case result := <-results: - checks[j] = result - - case <-time.After(time.Second): - t.Fatalf("test %d.%d: verification timeout", i, j) - } - } - // Check nonce check validity - for j := 0; j < len(blocks); j++ { - want := valid || (j < len(blocks)-2) // We chose the last-but-one nonce in the chain to fail - if (checks[j] == nil) != want { - t.Errorf("test %d.%d: validity mismatch: have %v, want %v", i, j, checks[j], want) - } - if !want { - // A few blocks after the first error may pass verification due to concurrent - // workers. We don't care about those in this test, just that the correct block - // errors out. - break - } - } - // Make sure no more data is returned - select { - case result := <-results: - t.Fatalf("test %d: unexpected result returned: %v", i, result) - case <-time.After(25 * time.Millisecond): - } - } -} - -// Tests that aborting a header validation indeed prevents further checks from being -// run, as well as checks that no left-over goroutines are leaked. -func TestHeaderConcurrentAbortion2(t *testing.T) { testHeaderConcurrentAbortion(t, 2) } -func TestHeaderConcurrentAbortion8(t *testing.T) { testHeaderConcurrentAbortion(t, 8) } -func TestHeaderConcurrentAbortion32(t *testing.T) { testHeaderConcurrentAbortion(t, 32) } - -func testHeaderConcurrentAbortion(t *testing.T, threads int) { - // Create a simple chain to verify - var ( - gspec = &Genesis{Config: params.TestChainConfig} - _, blocks, _ = GenerateChainWithGenesis(gspec, ethash.NewFaker(), 1024, nil) - ) - headers := make([]*types.Header, len(blocks)) - for i, block := range blocks { - headers[i] = block.Header() - } - // Set the number of threads to verify on - old := runtime.GOMAXPROCS(threads) - defer runtime.GOMAXPROCS(old) - - // Start the verifications and immediately abort - chain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, ethash.NewFakeDelayer(time.Millisecond), vm.Config{}, nil, nil) - defer chain.Stop() - - abort, results := chain.engine.VerifyHeaders(chain, headers) - close(abort) - - // Deplete the results channel - verified := 0 - for depleted := false; !depleted; { - select { - case result := <-results: - if result != nil { - t.Errorf("header %d: validation failed: %v", verified, result) - } - verified++ - case <-time.After(50 * time.Millisecond): - depleted = true - } - } - // Check that abortion was honored by not processing too many POWs - if verified > 2*threads { - t.Errorf("verification count too large: have %d, want below %d", verified, 2*threads) - } -} - func TestCalcGasLimit(t *testing.T) { for i, tc := range []struct { pGasLimit uint64 diff --git a/core/blockchain.go b/core/blockchain.go index 659b2f02ea..3e9440fed7 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -23,7 +23,6 @@ import ( "io" "math/big" "runtime" - "sort" "strings" "sync" "sync/atomic" @@ -34,6 +33,7 @@ import ( "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/common/prque" "github.com/ethereum/go-ethereum/consensus" + "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/state/snapshot" @@ -48,6 +48,9 @@ import ( "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" + "github.com/ethereum/go-ethereum/trie/triedb/hashdb" + "github.com/ethereum/go-ethereum/trie/triedb/pathdb" + "golang.org/x/exp/slices" ) var ( @@ -57,6 +60,8 @@ var ( headFinalizedBlockGauge = metrics.NewRegisteredGauge("chain/head/finalized", nil) headSafeBlockGauge = metrics.NewRegisteredGauge("chain/head/safe", nil) + 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) @@ -87,6 +92,8 @@ var ( errInsertionInterrupted = errors.New("insertion is interrupted") errChainStopped = errors.New("blockchain is stopped") + errInvalidOldChain = errors.New("invalid old chain") + errInvalidNewChain = errors.New("invalid new chain") ) const ( @@ -125,22 +132,40 @@ const ( ) // CacheConfig contains the configuration values for the trie database -// that's resident in a blockchain. +// and state snapshot these are resident in a blockchain. type CacheConfig struct { TrieCleanLimit int // Memory allowance (MB) to use for caching trie nodes in memory - TrieCleanJournal string // Disk journal for saving clean cache entries. - TrieCleanRejournal time.Duration // Time interval to dump clean cache to disk periodically TrieCleanNoPrefetch bool // Whether to disable heuristic state prefetching for followup blocks TrieDirtyLimit int // Memory limit (MB) at which to start flushing dirty trie nodes to disk TrieDirtyDisabled bool // Whether to disable trie write caching and GC altogether (archive node) TrieTimeLimit time.Duration // Time limit after which to flush the current in-memory trie to disk SnapshotLimit int // Memory allowance (MB) to use for caching snapshot entries in memory Preimages bool // Whether to store preimage of trie key to the disk + StateHistory uint64 // Number of blocks from head whose state histories are reserved. + StateScheme string // Scheme used to store ethereum states and merkle tree nodes on top SnapshotNoBuild bool // Whether the background generation is allowed SnapshotWait bool // Wait for snapshot construction on startup. TODO(karalabe): This is a dirty hack for testing, nuke it } +// triedbConfig derives the configures for trie database. +func (c *CacheConfig) triedbConfig() *trie.Config { + config := &trie.Config{Preimages: c.Preimages} + if c.StateScheme == rawdb.HashScheme { + config.HashDB = &hashdb.Config{ + CleanCacheSize: c.TrieCleanLimit * 1024 * 1024, + } + } + if c.StateScheme == rawdb.PathScheme { + config.PathDB = &pathdb.Config{ + StateHistory: c.StateHistory, + CleanCacheSize: c.TrieCleanLimit * 1024 * 1024, + DirtyCacheSize: c.TrieDirtyLimit * 1024 * 1024, + } + } + return config +} + // defaultCacheConfig are the default caching values if none are specified by the // user (also used during testing). var defaultCacheConfig = &CacheConfig{ @@ -149,6 +174,15 @@ var defaultCacheConfig = &CacheConfig{ TrieTimeLimit: 5 * time.Minute, SnapshotLimit: 256, SnapshotWait: true, + StateScheme: rawdb.HashScheme, +} + +// DefaultCacheConfigWithScheme returns a deep copied default cache config with +// a provided trie node scheme. +func DefaultCacheConfigWithScheme(scheme string) *CacheConfig { + config := *defaultCacheConfig + config.StateScheme = scheme + return &config } // BlockChain represents the canonical chain given a database with a genesis @@ -234,11 +268,8 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis cacheConfig = defaultCacheConfig } // Open trie database with provided config - triedb := trie.NewDatabaseWithConfig(db, &trie.Config{ - Cache: cacheConfig.TrieCleanLimit, - Journal: cacheConfig.TrieCleanJournal, - Preimages: cacheConfig.Preimages, - }) + triedb := trie.NewDatabase(db, cacheConfig.triedbConfig()) + // Setup the genesis block, commit the provided genesis specification // to database if the genesis block is not present yet, or load the // stored one from database. @@ -293,6 +324,9 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis bc.currentFinalBlock.Store(nil) bc.currentSafeBlock.Store(nil) + // Update chain info data metrics + chainInfoGauge.Update(metrics.GaugeInfoValue{"chain_id": bc.chainConfig.ChainID.String()}) + // If Geth is initialized with an external ancient store, re-initialize the // missing chain indexes and chain flags. This procedure can survive crash // and can be resumed in next restart since chain flags are updated in last step. @@ -345,7 +379,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis needRewind = true low = fullBlock.Number.Uint64() } - // In fast sync, it may happen that ancient data has been written to the + // In snap sync, it may happen that ancient data has been written to the // ancient store, but the LastFastBlock has not been updated, truncate the // extra data here. snapBlock := bc.CurrentSnapBlock() @@ -409,18 +443,6 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis bc.wg.Add(1) go bc.updateFutureBlocks() - // If periodic cache journal is required, spin it up. - if bc.cacheConfig.TrieCleanRejournal > 0 { - if bc.cacheConfig.TrieCleanRejournal < time.Minute { - log.Warn("Sanitizing invalid trie cache journal time", "provided", bc.cacheConfig.TrieCleanRejournal, "updated", time.Minute) - bc.cacheConfig.TrieCleanRejournal = time.Minute - } - bc.wg.Add(1) - go func() { - defer bc.wg.Done() - bc.triedb.SaveCachePeriodically(bc.cacheConfig.TrieCleanJournal, bc.cacheConfig.TrieCleanRejournal, bc.quit) - }() - } // 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) @@ -485,7 +507,7 @@ func (bc *BlockChain) loadLastState() error { } bc.hc.SetCurrentHeader(headHeader) - // Restore the last known head fast block + // Restore the last known head snap block bc.currentSnapBlock.Store(headBlock.Header()) headFastBlockGauge.Update(int64(headBlock.NumberU64())) @@ -520,21 +542,21 @@ func (bc *BlockChain) loadLastState() error { } log.Info("Loaded most recent local block", "number", headBlock.Number(), "hash", headBlock.Hash(), "td", blockTd, "age", common.PrettyAge(time.Unix(int64(headBlock.Time()), 0))) if headBlock.Hash() != currentSnapBlock.Hash() { - fastTd := bc.GetTd(currentSnapBlock.Hash(), currentSnapBlock.Number.Uint64()) - log.Info("Loaded most recent local snap block", "number", currentSnapBlock.Number, "hash", currentSnapBlock.Hash(), "td", fastTd, "age", common.PrettyAge(time.Unix(int64(currentSnapBlock.Time), 0))) + snapTd := bc.GetTd(currentSnapBlock.Hash(), currentSnapBlock.Number.Uint64()) + log.Info("Loaded most recent local snap block", "number", currentSnapBlock.Number, "hash", currentSnapBlock.Hash(), "td", snapTd, "age", common.PrettyAge(time.Unix(int64(currentSnapBlock.Time), 0))) } if currentFinalBlock != nil { finalTd := bc.GetTd(currentFinalBlock.Hash(), currentFinalBlock.Number.Uint64()) log.Info("Loaded most recent local finalized block", "number", currentFinalBlock.Number, "hash", currentFinalBlock.Hash(), "td", finalTd, "age", common.PrettyAge(time.Unix(int64(currentFinalBlock.Time), 0))) } if pivot := rawdb.ReadLastPivotNumber(bc.db); pivot != nil { - log.Info("Loaded last fast-sync pivot marker", "number", *pivot) + log.Info("Loaded last snap-sync pivot marker", "number", *pivot) } return nil } // SetHead rewinds the local chain to a new head. Depending on whether the node -// was fast synced or full synced and in which state, the method will try to +// was snap synced or full synced and in which state, the method will try to // delete minimal data from disk whilst retaining chain consistency. func (bc *BlockChain) SetHead(head uint64) error { if _, err := bc.setHeadBeyondRoot(head, 0, common.Hash{}, false); err != nil { @@ -555,7 +577,7 @@ func (bc *BlockChain) SetHead(head uint64) error { } // SetHeadWithTimestamp rewinds the local chain to a new head that has at max -// the given timestamp. Depending on whether the node was fast synced or full +// the given timestamp. Depending on whether the node was snap synced or full // synced and in which state, the method will try to delete minimal data from // disk whilst retaining chain consistency. func (bc *BlockChain) SetHeadWithTimestamp(timestamp uint64) error { @@ -601,7 +623,7 @@ func (bc *BlockChain) SetSafe(header *types.Header) { // 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 -// persistent disk layer. Depending on whether the node was fast synced or full, and +// persistent disk layer. Depending on whether the node was snap synced or full, and // in which state, the method will try to delete minimal data from disk whilst // retaining chain consistency. // @@ -624,6 +646,25 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha pivot := rawdb.ReadLastPivotNumber(bc.db) frozen, _ := bc.db.Ancients() + // resetState resets the persistent state to genesis if it's not available. + resetState := func() { + // Short circuit if the genesis state is already present. + if bc.HasState(bc.genesisBlock.Root()) { + return + } + // Reset the state database to empty for committing genesis state. + // Note, it should only happen in path-based scheme and Reset function + // is also only call-able in this mode. + if bc.triedb.Scheme() == rawdb.PathScheme { + if err := bc.triedb.Reset(types.EmptyRootHash); err != nil { + log.Crit("Failed to clean state", "err", err) // Shouldn't happen + } + } + // Write genesis state into database. + if err := CommitGenesisState(bc.db, bc.triedb, bc.genesisBlock.Hash()); err != nil { + log.Crit("Failed to commit genesis state", "err", err) + } + } 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 @@ -633,6 +674,7 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha if newHeadBlock == nil { log.Error("Gap in the chain, rewinding to genesis", "number", header.Number, "hash", header.Hash()) newHeadBlock = bc.genesisBlock + resetState() } else { // Block exists, keep rewinding until we find one with state, // keeping rewinding until we exceed the optional threshold @@ -644,7 +686,7 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha if root != (common.Hash{}) && !beyondRoot && newHeadBlock.Root() == root { beyondRoot, rootNumber = true, newHeadBlock.NumberU64() } - if !bc.HasState(newHeadBlock.Root()) { + 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) @@ -661,16 +703,12 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha } if beyondRoot || newHeadBlock.NumberU64() == 0 { if newHeadBlock.NumberU64() == 0 { - // Recommit the genesis state into disk in case the rewinding destination - // is genesis block and the relevant state is gone. In the future this - // rewinding destination can be the earliest block stored in the chain - // if the historical chain pruning is enabled. In that case the logic - // needs to be improved here. - if !bc.HasState(bc.genesisBlock.Root()) { - if err := CommitGenesisState(bc.db, bc.triedb, bc.genesisBlock.Hash()); err != nil { - log.Crit("Failed to commit genesis state", "err", err) - } - log.Debug("Recommitted genesis state to disk") + resetState() + } else if !bc.HasState(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()) @@ -689,7 +727,7 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha bc.currentBlock.Store(newHeadBlock.Header()) headBlockGauge.Update(int64(newHeadBlock.NumberU64())) } - // Rewind the fast block in a simpleton way to the target head + // Rewind the snap block in a simpleton way to the target head if currentSnapBlock := bc.CurrentSnapBlock(); currentSnapBlock != nil && header.Number.Uint64() < currentSnapBlock.Number.Uint64() { newHeadSnapBlock := bc.GetBlock(header.Hash(), header.Number.Uint64()) // If either blocks reached nil, reset to the genesis state @@ -725,7 +763,7 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha if num+1 <= frozen { // Truncate all relative data(header, total difficulty, body, receipt // and canonical hash) from ancient store. - if err := bc.db.TruncateHead(num); err != nil { + if _, err := bc.db.TruncateHead(num); err != nil { log.Crit("Failed to truncate ancient data", "number", num, "err", err) } // Remove the hash <-> number mapping from the active store. @@ -747,7 +785,7 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha } } else { // Rewind the chain to the requested head and keep going backwards until a - // block with a state is found or fast sync pivot is passed + // block with a state is found or snap sync pivot is passed if time > 0 { log.Warn("Rewinding blockchain to timestamp", "target", time) bc.hc.SetHeadWithTimestamp(time, updateFn, delFn) @@ -784,7 +822,13 @@ func (bc *BlockChain) SnapSyncCommitHead(hash common.Hash) error { if block == nil { return fmt.Errorf("non existent block [%x..]", hash[:4]) } + // Reset the trie database with the fresh snap synced state. root := block.Root() + if bc.triedb.Scheme() == rawdb.PathScheme { + if err := bc.triedb.Reset(root); err != nil { + return err + } + } if !bc.HasState(root) { return fmt.Errorf("non existent state [%x..]", root[:4]) } @@ -865,7 +909,7 @@ func (bc *BlockChain) ExportN(w io.Writer, first uint64, last uint64) error { return fmt.Errorf("export failed on #%d: not found", nr) } if nr > first && block.ParentHash() != parentHash { - return fmt.Errorf("export failed: chain reorg during export") + return errors.New("export failed: chain reorg during export") } parentHash = block.Hash() if err := block.EncodeRLP(w); err != nil { @@ -881,7 +925,7 @@ func (bc *BlockChain) ExportN(w io.Writer, first uint64, last uint64) error { // writeHeadBlock injects a new head block into the current block chain. This method // assumes that the block is indeed a true head. It will also reset the head -// header and the head fast sync block to this very same block if they are older +// header and the head snap sync block to this very same block if they are older // or if they are on a different side chain. // // Note, this function assumes that the `mu` mutex is held! @@ -949,46 +993,47 @@ func (bc *BlockChain) Stop() { log.Error("Failed to journal state snapshot", "err", err) } } + if bc.triedb.Scheme() == rawdb.PathScheme { + // Ensure that the in-memory trie nodes are journaled to disk properly. + if err := bc.triedb.Journal(bc.CurrentBlock().Root); err != nil { + log.Info("Failed to journal in-memory trie nodes", "err", err) + } + } else { + // Ensure the state of a recent block is also stored to disk before exiting. + // We're writing three different states to catch different restart scenarios: + // - HEAD: So we don't need to reprocess any blocks in the general case + // - HEAD-1: So we don't do large reorgs if our HEAD becomes an uncle + // - HEAD-127: So we have a hard limit on the number of blocks reexecuted + if !bc.cacheConfig.TrieDirtyDisabled { + triedb := bc.triedb - // Ensure the state of a recent block is also stored to disk before exiting. - // We're writing three different states to catch different restart scenarios: - // - HEAD: So we don't need to reprocess any blocks in the general case - // - HEAD-1: So we don't do large reorgs if our HEAD becomes an uncle - // - HEAD-127: So we have a hard limit on the number of blocks reexecuted - if !bc.cacheConfig.TrieDirtyDisabled { - triedb := bc.triedb + for _, offset := range []uint64{0, 1, TriesInMemory - 1} { + if number := bc.CurrentBlock().Number.Uint64(); number > offset { + recent := bc.GetBlockByNumber(number - offset) - for _, offset := range []uint64{0, 1, TriesInMemory - 1} { - if number := bc.CurrentBlock().Number.Uint64(); number > offset { - recent := bc.GetBlockByNumber(number - offset) - - log.Info("Writing cached state to disk", "block", recent.Number(), "hash", recent.Hash(), "root", recent.Root()) - if err := triedb.Commit(recent.Root(), true); err != nil { + log.Info("Writing cached state to disk", "block", recent.Number(), "hash", recent.Hash(), "root", recent.Root()) + if err := triedb.Commit(recent.Root(), true); err != nil { + log.Error("Failed to commit recent state trie", "err", err) + } + } + } + if snapBase != (common.Hash{}) { + log.Info("Writing snapshot state to disk", "root", snapBase) + if err := triedb.Commit(snapBase, true); err != nil { log.Error("Failed to commit recent state trie", "err", err) } } - } - if snapBase != (common.Hash{}) { - log.Info("Writing snapshot state to disk", "root", snapBase) - if err := triedb.Commit(snapBase, true); err != nil { - log.Error("Failed to commit recent state trie", "err", err) + for !bc.triegc.Empty() { + triedb.Dereference(bc.triegc.PopItem()) + } + if _, nodes, _ := triedb.Size(); nodes != 0 { // all memory is contained within the nodes return for hashdb + log.Error("Dangling trie nodes after full cleanup") } } - for !bc.triegc.Empty() { - triedb.Dereference(bc.triegc.PopItem()) - } - if size, _ := triedb.Size(); size != 0 { - log.Error("Dangling trie nodes after full cleanup") - } } - // Flush the collected preimages to disk - if err := bc.stateCache.TrieDB().Close(); err != nil { - log.Error("Failed to close trie db", "err", err) - } - // Ensure all live cached entries be saved into disk, so that we can skip - // cache warmup when node restarts. - if bc.cacheConfig.TrieCleanJournal != "" { - bc.triedb.SaveCache(bc.cacheConfig.TrieCleanJournal) + // 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) } log.Info("Blockchain stopped") } @@ -1013,8 +1058,8 @@ func (bc *BlockChain) procFutureBlocks() { } } if len(blocks) > 0 { - sort.Slice(blocks, func(i, j int) bool { - return blocks[i].NumberU64() < blocks[j].NumberU64() + 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 { @@ -1045,19 +1090,30 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ ancientReceipts, liveReceipts []types.Receipts ) // Do a sanity check that the provided chain is actually ordered and linked - for i := 0; i < len(blockChain); i++ { + for i, block := range blockChain { if i != 0 { - if blockChain[i].NumberU64() != blockChain[i-1].NumberU64()+1 || blockChain[i].ParentHash() != blockChain[i-1].Hash() { - log.Error("Non contiguous receipt insert", "number", blockChain[i].Number(), "hash", blockChain[i].Hash(), "parent", blockChain[i].ParentHash(), - "prevnumber", blockChain[i-1].Number(), "prevhash", blockChain[i-1].Hash()) - return 0, fmt.Errorf("non contiguous insert: item %d is #%d [%x..], item %d is #%d [%x..] (parent [%x..])", i-1, blockChain[i-1].NumberU64(), - blockChain[i-1].Hash().Bytes()[:4], i, blockChain[i].NumberU64(), blockChain[i].Hash().Bytes()[:4], blockChain[i].ParentHash().Bytes()[:4]) + prev := blockChain[i-1] + if block.NumberU64() != prev.NumberU64()+1 || block.ParentHash() != prev.Hash() { + log.Error("Non contiguous receipt insert", + "number", block.Number(), "hash", block.Hash(), "parent", block.ParentHash(), + "prevnumber", prev.Number(), "prevhash", prev.Hash()) + return 0, fmt.Errorf("non contiguous insert: item %d is #%d [%x..], item %d is #%d [%x..] (parent [%x..])", + i-1, prev.NumberU64(), prev.Hash().Bytes()[:4], + i, block.NumberU64(), block.Hash().Bytes()[:4], block.ParentHash().Bytes()[:4]) } } - if blockChain[i].NumberU64() <= ancientLimit { - ancientBlocks, ancientReceipts = append(ancientBlocks, blockChain[i]), append(ancientReceipts, receiptChain[i]) + if block.NumberU64() <= ancientLimit { + ancientBlocks, ancientReceipts = append(ancientBlocks, block), append(ancientReceipts, receiptChain[i]) } else { - liveBlocks, liveReceipts = append(liveBlocks, blockChain[i]), append(liveReceipts, receiptChain[i]) + liveBlocks, liveReceipts = append(liveBlocks, block), append(liveReceipts, receiptChain[i]) + } + + // Here we also validate that blob transactions in the block do not contain a sidecar. + // While the sidecar does not affect the block hash / tx hash, sending blobs within a block is not allowed. + for txIndex, tx := range block.Transactions() { + if tx.Type() == types.BlobTxType && tx.BlobTxSidecar() != nil { + return 0, fmt.Errorf("block #%d contains unexpected blob sidecar in tx at index %d", block.NumberU64(), txIndex) + } } } @@ -1067,7 +1123,7 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ size = int64(0) ) - // updateHead updates the head fast sync block if the inserted blocks are better + // updateHead updates the head snap sync block if the inserted blocks are better // and returns an indicator whether the inserted blocks are canonical. updateHead := func(head *types.Block) bool { if !bc.chainmu.TryLock() { @@ -1153,7 +1209,7 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ size += int64(batch.ValueSize()) if err = batch.Write(); err != nil { snapBlock := bc.CurrentSnapBlock().Number.Uint64() - if err := bc.db.TruncateHead(snapBlock + 1); err != nil { + if _, err := bc.db.TruncateHead(snapBlock + 1); err != nil { log.Error("Can't truncate ancient store after failed insert", "err", err) } return 0, err @@ -1166,12 +1222,12 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ if err := bc.db.Sync(); err != nil { return 0, err } - // Update the current fast block because all block data is now present in DB. + // Update the current snap block because all block data is now present in DB. previousSnapBlock := bc.CurrentSnapBlock().Number.Uint64() if !updateHead(blockChain[len(blockChain)-1]) { // We end up here if the header chain has reorg'ed, and the blocks/receipts // don't match the canonical chain. - if err := bc.db.TruncateHead(previousSnapBlock + 1); err != nil { + if _, err := bc.db.TruncateHead(previousSnapBlock + 1); err != nil { log.Error("Can't truncate ancient store after failed insert", "err", err) } return 0, errSideChainReceipts @@ -1354,10 +1410,15 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. log.Crit("Failed to write block into disk", "err", err) } // Commit all cached state changes into underlying memory database. - root, err := state.Commit(bc.chainConfig.IsEIP158(block.Number())) + root, err := state.Commit(block.NumberU64(), bc.chainConfig.IsEIP158(block.Number())) if err != nil { return err } + // If node is running in path mode, skip explicit gc operation + // which is unnecessary in this mode. + if bc.triedb.Scheme() == rawdb.PathScheme { + return nil + } // If we're running an archive node, always flush if bc.cacheConfig.TrieDirtyDisabled { return bc.triedb.Commit(root, false) @@ -1366,15 +1427,15 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. bc.triedb.Reference(root, common.Hash{}) // metadata reference to keep trie alive bc.triegc.Push(root, -int64(block.NumberU64())) - current := block.NumberU64() // Flush limits are not considered for the first TriesInMemory blocks. + current := block.NumberU64() if current <= TriesInMemory { return nil } // If we exceeded our memory allowance, flush matured singleton nodes to disk var ( - nodes, imgs = bc.triedb.Size() - limit = common.StorageSize(bc.cacheConfig.TrieDirtyLimit) * 1024 * 1024 + _, nodes, imgs = bc.triedb.Size() // all memory is contained within the nodes return for hashdb + limit = common.StorageSize(bc.cacheConfig.TrieDirtyLimit) * 1024 * 1024 ) if nodes > limit || imgs > 4*1024*1024 { bc.triedb.Cap(limit - ethdb.IdealBatchSize) @@ -1596,11 +1657,11 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) block, err = it.next() } // The remaining blocks are still known blocks, the only scenario here is: - // During the fast sync, the pivot point is already submitted but rollback + // During the snap sync, the pivot point is already submitted but rollback // happens. Then node resets the head full block to a lower height via `rollback` // and leaves a few known blocks in the database. // - // When node runs a fast sync again, it can re-import a batch of known blocks via + // When node runs a snap sync again, it can re-import a batch of known blocks via // `insertChain` while a part of them have higher total difficulty than current // head full block(new pivot point). for block != nil && bc.skipBlock(err, it) { @@ -1810,8 +1871,12 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) stats.processed++ stats.usedGas += usedGas - dirty, _ := bc.triedb.Size() - stats.report(chain, it.index, dirty, setHead) + var snapDiffItems, snapBufItems common.StorageSize + if bc.snaps != nil { + snapDiffItems, snapBufItems = bc.snaps.Size() + } + trieDiffNodes, trieBufNodes, _ := bc.triedb.Size() + stats.report(chain, it.index, snapDiffItems, snapBufItems, trieDiffNodes, trieBufNodes, setHead) if !setHead { // After merge we expect few side chains. Simply count @@ -1953,6 +2018,12 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i ) parent := it.previous() for parent != nil && !bc.HasState(parent.Root) { + if bc.stateRecoverable(parent.Root) { + if err := bc.triedb.Recover(parent.Root); err != nil { + return 0, err + } + break + } hashes = append(hashes, parent.Hash()) numbers = append(numbers, parent.Number.Uint64()) @@ -2009,6 +2080,12 @@ func (bc *BlockChain) recoverAncestors(block *types.Block) (common.Hash, error) parent = block ) for parent != nil && !bc.HasState(parent.Root()) { + if bc.stateRecoverable(parent.Root()) { + if err := bc.triedb.Recover(parent.Root()); err != nil { + return common.Hash{}, err + } + break + } hashes = append(hashes, parent.Hash()) numbers = append(numbers, parent.NumberU64()) parent = bc.GetBlock(parent.ParentHash(), parent.NumberU64()-1) @@ -2045,17 +2122,22 @@ func (bc *BlockChain) recoverAncestors(block *types.Block) (common.Hash, error) // collectLogs collects the logs that were generated or removed during // the processing of a block. These logs are later announced as deleted or reborn. func (bc *BlockChain) collectLogs(b *types.Block, removed bool) []*types.Log { + var blobGasPrice *big.Int + excessBlobGas := b.ExcessBlobGas() + if excessBlobGas != nil { + blobGasPrice = eip4844.CalcBlobFee(*excessBlobGas) + } receipts := rawdb.ReadRawReceipts(bc.db, b.Hash(), b.NumberU64()) - receipts.DeriveFields(bc.chainConfig, b.Hash(), b.NumberU64(), b.Time(), b.BaseFee(), b.Transactions()) - + if err := receipts.DeriveFields(bc.chainConfig, b.Hash(), b.NumberU64(), b.Time(), b.BaseFee(), blobGasPrice, b.Transactions()); err != nil { + log.Error("Failed to derive block receipts fields", "hash", b.Hash(), "number", b.NumberU64(), "err", err) + } var logs []*types.Log for _, receipt := range receipts { for _, log := range receipt.Logs { - l := *log if removed { - l.Removed = true + log.Removed = true } - logs = append(logs, &l) + logs = append(logs, log) } } return logs @@ -2097,10 +2179,10 @@ func (bc *BlockChain) reorg(oldHead *types.Header, newHead *types.Block) error { } } if oldBlock == nil { - return errors.New("invalid old chain") + return errInvalidOldChain } if newBlock == nil { - return errors.New("invalid new chain") + return errInvalidNewChain } // Both sides of the reorg are at the same number, reduce both until the common // ancestor is found @@ -2120,11 +2202,11 @@ func (bc *BlockChain) reorg(oldHead *types.Header, newHead *types.Block) error { // Step back with both chains oldBlock = bc.GetBlock(oldBlock.ParentHash(), oldBlock.NumberU64()-1) if oldBlock == nil { - return fmt.Errorf("invalid old chain") + return errInvalidOldChain } newBlock = bc.GetBlock(newBlock.ParentHash(), newBlock.NumberU64()-1) if newBlock == nil { - return fmt.Errorf("invalid new chain") + return errInvalidNewChain } } @@ -2348,6 +2430,12 @@ func (bc *BlockChain) skipBlock(err error, it *insertIterator) bool { func (bc *BlockChain) indexBlocks(tail *uint64, head uint64, done chan struct{}) { defer func() { close(done) }() + // If head is 0, it means the chain is just initialized and no blocks are inserted, + // so don't need to indexing anything. + if head == 0 { + return + } + // The tail flag is not existent, it means the node is just initialized // and all blocks(may from ancient store) are not indexed yet. if tail == nil { @@ -2405,6 +2493,15 @@ func (bc *BlockChain) maintainTxIndex() { return } defer sub.Unsubscribe() + log.Info("Initialized transaction indexer", "limit", bc.TxLookupLimit()) + + // Launch the initial processing if chain is not empty. This step is + // useful in these scenarios that chain has no progress and indexer + // is never triggered. + if head := rawdb.ReadHeadBlock(bc.db); head != nil { + done = make(chan struct{}) + go bc.indexBlocks(rawdb.ReadTxIndexTail(bc.db), head.NumberU64(), done) + } for { select { @@ -2490,3 +2587,8 @@ func (bc *BlockChain) SetBlockValidatorAndProcessorForTesting(v Validator, p Pro func (bc *BlockChain) SetTrieFlushInterval(interval time.Duration) { bc.flushInterval.Store(int64(interval)) } + +// GetTrieFlushInterval gets the in-memroy tries flush interval +func (bc *BlockChain) GetTrieFlushInterval() time.Duration { + return time.Duration(bc.flushInterval.Load()) +} diff --git a/core/blockchain_insert.go b/core/blockchain_insert.go index 8f496e182c..9bf662b6b7 100644 --- a/core/blockchain_insert.go +++ b/core/blockchain_insert.go @@ -39,7 +39,7 @@ const statsReportLimit = 8 * time.Second // report prints statistics if some number of blocks have been processed // or more than a few seconds have passed since the last message. -func (st *insertStats) report(chain []*types.Block, index int, dirty common.StorageSize, setHead bool) { +func (st *insertStats) report(chain []*types.Block, index int, snapDiffItems, snapBufItems, trieDiffNodes, triebufNodes common.StorageSize, setHead bool) { // Fetch the timings for the batch var ( now = mclock.Now() @@ -63,7 +63,16 @@ func (st *insertStats) report(chain []*types.Block, index int, dirty common.Stor if timestamp := time.Unix(int64(end.Time()), 0); time.Since(timestamp) > time.Minute { context = append(context, []interface{}{"age", common.PrettyAge(timestamp)}...) } - context = append(context, []interface{}{"dirty", dirty}...) + if snapDiffItems != 0 || snapBufItems != 0 { // snapshots enabled + context = append(context, []interface{}{"snapdiffs", snapDiffItems}...) + if snapBufItems != 0 { // future snapshot refactor + context = append(context, []interface{}{"snapdirty", snapBufItems}...) + } + } + if trieDiffNodes != 0 { // pathdb + context = append(context, []interface{}{"triediffs", trieDiffNodes}...) + } + context = append(context, []interface{}{"triedirty", triebufNodes}...) if st.queued > 0 { context = append(context, []interface{}{"queued", st.queued}...) diff --git a/core/blockchain_reader.go b/core/blockchain_reader.go index fd65cb2db3..466a86c144 100644 --- a/core/blockchain_reader.go +++ b/core/blockchain_reader.go @@ -293,10 +293,16 @@ func (bc *BlockChain) HasBlockAndState(hash common.Hash, number uint64) bool { return bc.HasState(block.Root()) } -// TrieNode retrieves a blob of data associated with a trie node -// either from ephemeral in-memory cache, or from persistent storage. -func (bc *BlockChain) TrieNode(hash common.Hash) ([]byte, error) { - return bc.stateCache.TrieDB().Node(hash) +// stateRecoverable checks if the specified state is recoverable. +// Note, this function assumes the state is not present, because +// state is not treated as recoverable if it's available, thus +// false will be returned in this case. +func (bc *BlockChain) stateRecoverable(root common.Hash) bool { + if bc.triedb.Scheme() == rawdb.HashScheme { + return false + } + result, _ := bc.triedb.Recoverable(root) + return result } // ContractCodeWithPrefix retrieves a blob of data associated with a contract @@ -306,9 +312,11 @@ func (bc *BlockChain) TrieNode(hash common.Hash) ([]byte, error) { // new code scheme. func (bc *BlockChain) ContractCodeWithPrefix(hash common.Hash) ([]byte, error) { type codeReader interface { - ContractCodeWithPrefix(addrHash, codeHash common.Hash) ([]byte, error) + ContractCodeWithPrefix(address common.Address, codeHash common.Hash) ([]byte, error) } - return bc.stateCache.(codeReader).ContractCodeWithPrefix(common.Hash{}, hash) + // 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) } // State returns a new mutable state based on the current HEAD block. diff --git a/core/blockchain_repair_test.go b/core/blockchain_repair_test.go index 6a4a9c9d22..b2df39d17b 100644 --- a/core/blockchain_repair_test.go +++ b/core/blockchain_repair_test.go @@ -22,6 +22,7 @@ package core import ( "math/big" + "path" "testing" "time" @@ -1749,16 +1750,24 @@ func testLongReorgedSnapSyncingDeepRepair(t *testing.T, snapshots bool) { } func testRepair(t *testing.T, tt *rewindTest, snapshots bool) { + for _, scheme := range []string{rawdb.HashScheme, rawdb.PathScheme} { + testRepairWithScheme(t, tt, snapshots, scheme) + } +} + +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)) // Create a temporary persistent database datadir := t.TempDir() + ancient := path.Join(datadir, "ancient") db, err := rawdb.Open(rawdb.OpenOptions{ Directory: datadir, - AncientsDirectory: datadir, + AncientsDirectory: ancient, + Ephemeral: true, }) if err != nil { t.Fatalf("Failed to create persistent database: %v", err) @@ -1777,6 +1786,7 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) { TrieDirtyLimit: 256, TrieTimeLimit: 5 * time.Minute, SnapshotLimit: 0, // Disable snapshot by default + StateScheme: scheme, } ) defer engine.Close() @@ -1806,7 +1816,9 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) { t.Fatalf("Failed to import canonical chain start: %v", err) } if tt.commitBlock > 0 { - chain.stateCache.TrieDB().Commit(canonblocks[tt.commitBlock-1].Root(), false) + if err := chain.triedb.Commit(canonblocks[tt.commitBlock-1].Root(), false); err != nil { + t.Fatalf("Failed to flush trie state: %v", err) + } if snapshots { if err := chain.snaps.Cap(canonblocks[tt.commitBlock-1].Root(), 0); err != nil { t.Fatalf("Failed to flatten snapshots: %v", err) @@ -1828,21 +1840,22 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) { rawdb.WriteLastPivotNumber(db, *tt.pivotBlock) } // Pull the plug on the database, simulating a hard crash + chain.triedb.Close() db.Close() chain.stopWithoutSaving() // Start a new blockchain back up and see where the repair leads us db, err = rawdb.Open(rawdb.OpenOptions{ Directory: datadir, - AncientsDirectory: datadir, + AncientsDirectory: ancient, + Ephemeral: true, }) - if err != nil { t.Fatalf("Failed to reopen persistent database: %v", err) } defer db.Close() - newChain, err := NewBlockChain(db, nil, gspec, nil, engine, vm.Config{}, nil, nil) + newChain, err := NewBlockChain(db, config, gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } @@ -1885,17 +1898,22 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) { // In this case the snapshot layer of B3 is not created because of existent // state. func TestIssue23496(t *testing.T) { + testIssue23496(t, rawdb.HashScheme) + testIssue23496(t, rawdb.PathScheme) +} + +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)))) // Create a temporary persistent database datadir := t.TempDir() + ancient := path.Join(datadir, "ancient") db, err := rawdb.Open(rawdb.OpenOptions{ Directory: datadir, - AncientsDirectory: datadir, + AncientsDirectory: ancient, }) - if err != nil { t.Fatalf("Failed to create persistent database: %v", err) } @@ -1908,15 +1926,8 @@ func TestIssue23496(t *testing.T) { BaseFee: big.NewInt(params.InitialBaseFee), } engine = ethash.NewFullFaker() - config = &CacheConfig{ - TrieCleanLimit: 256, - TrieDirtyLimit: 256, - TrieTimeLimit: 5 * time.Minute, - SnapshotLimit: 256, - SnapshotWait: true, - } ) - chain, err := NewBlockChain(db, config, gspec, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("Failed to create chain: %v", err) } @@ -1929,7 +1940,7 @@ func TestIssue23496(t *testing.T) { if _, err := chain.InsertChain(blocks[:1]); err != nil { t.Fatalf("Failed to import canonical chain start: %v", err) } - chain.stateCache.TrieDB().Commit(blocks[0].Root(), false) + chain.triedb.Commit(blocks[0].Root(), false) // Insert block B2 and commit the snapshot into disk if _, err := chain.InsertChain(blocks[1:2]); err != nil { @@ -1943,7 +1954,7 @@ func TestIssue23496(t *testing.T) { if _, err := chain.InsertChain(blocks[2:3]); err != nil { t.Fatalf("Failed to import canonical chain start: %v", err) } - chain.stateCache.TrieDB().Commit(blocks[2].Root(), false) + chain.triedb.Commit(blocks[2].Root(), false) // Insert the remaining blocks if _, err := chain.InsertChain(blocks[3:]); err != nil { @@ -1951,20 +1962,22 @@ func TestIssue23496(t *testing.T) { } // Pull the plug on the database, simulating a hard crash + chain.triedb.Close() db.Close() chain.stopWithoutSaving() // Start a new blockchain back up and see where the repair leads us db, err = rawdb.Open(rawdb.OpenOptions{ Directory: datadir, - AncientsDirectory: datadir, + AncientsDirectory: ancient, + Ephemeral: true, }) if err != nil { t.Fatalf("Failed to reopen persistent database: %v", err) } defer db.Close() - chain, err = NewBlockChain(db, nil, gspec, nil, engine, vm.Config{}, nil, nil) + chain, err = NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } @@ -1976,8 +1989,12 @@ func TestIssue23496(t *testing.T) { if head := chain.CurrentSnapBlock(); head.Number.Uint64() != uint64(4) { t.Errorf("Head fast block mismatch: have %d, want %d", head.Number, uint64(4)) } - if head := chain.CurrentBlock(); head.Number.Uint64() != uint64(1) { - t.Errorf("Head block mismatch: have %d, want %d", head.Number, uint64(1)) + expHead := uint64(1) + if scheme == rawdb.PathScheme { + expHead = uint64(2) + } + if head := chain.CurrentBlock(); head.Number.Uint64() != expHead { + t.Errorf("Head block mismatch: have %d, want %d", head.Number, expHead) } // Reinsert B2-B4 diff --git a/core/blockchain_sethead_test.go b/core/blockchain_sethead_test.go index 9dc350db84..fa739f924f 100644 --- a/core/blockchain_sethead_test.go +++ b/core/blockchain_sethead_test.go @@ -22,6 +22,7 @@ package core import ( "fmt" "math/big" + "path" "strings" "testing" "time" @@ -29,9 +30,13 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus/ethash" "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/params" + "github.com/ethereum/go-ethereum/trie" + "github.com/ethereum/go-ethereum/trie/triedb/hashdb" + "github.com/ethereum/go-ethereum/trie/triedb/pathdb" ) // rewindTest is a test case for chain rollback upon user request. @@ -1949,16 +1954,24 @@ func testLongReorgedSnapSyncingDeepSetHead(t *testing.T, snapshots bool) { } func testSetHead(t *testing.T, tt *rewindTest, snapshots bool) { + for _, scheme := range []string{rawdb.HashScheme, rawdb.PathScheme} { + testSetHeadWithScheme(t, tt, snapshots, scheme) + } +} + +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)))) // fmt.Println(tt.dump(false)) // Create a temporary persistent database datadir := t.TempDir() + ancient := path.Join(datadir, "ancient") db, err := rawdb.Open(rawdb.OpenOptions{ Directory: datadir, - AncientsDirectory: datadir, + AncientsDirectory: ancient, + Ephemeral: true, }) if err != nil { t.Fatalf("Failed to create persistent database: %v", err) @@ -1977,6 +1990,7 @@ func testSetHead(t *testing.T, tt *rewindTest, snapshots bool) { TrieDirtyLimit: 256, TrieTimeLimit: 5 * time.Minute, SnapshotLimit: 0, // Disable snapshot + StateScheme: scheme, } ) if snapshots { @@ -2007,7 +2021,7 @@ func testSetHead(t *testing.T, tt *rewindTest, snapshots bool) { t.Fatalf("Failed to import canonical chain start: %v", err) } if tt.commitBlock > 0 { - chain.stateCache.TrieDB().Commit(canonblocks[tt.commitBlock-1].Root(), false) + chain.triedb.Commit(canonblocks[tt.commitBlock-1].Root(), false) if snapshots { if err := chain.snaps.Cap(canonblocks[tt.commitBlock-1].Root(), 0); err != nil { t.Fatalf("Failed to flatten snapshots: %v", err) @@ -2017,13 +2031,17 @@ func testSetHead(t *testing.T, tt *rewindTest, snapshots bool) { if _, err := chain.InsertChain(canonblocks[tt.commitBlock:]); err != nil { t.Fatalf("Failed to import canonical chain tail: %v", err) } - // Manually dereference anything not committed to not have to work with 128+ tries - for _, block := range sideblocks { - chain.stateCache.TrieDB().Dereference(block.Root()) - } - for _, block := range canonblocks { - chain.stateCache.TrieDB().Dereference(block.Root()) + // Reopen the trie database without persisting in-memory dirty nodes. + chain.triedb.Close() + dbconfig := &trie.Config{} + if scheme == rawdb.PathScheme { + dbconfig.PathDB = pathdb.Defaults + } else { + dbconfig.HashDB = hashdb.Defaults } + chain.triedb = trie.NewDatabase(chain.db, dbconfig) + chain.stateCache = state.NewDatabaseWithNodeDB(chain.db, chain.triedb) + // Force run a freeze cycle type freezer interface { Freeze(threshold uint64) error diff --git a/core/blockchain_snapshot_test.go b/core/blockchain_snapshot_test.go index 3bd876a58e..dd012c430c 100644 --- a/core/blockchain_snapshot_test.go +++ b/core/blockchain_snapshot_test.go @@ -24,6 +24,7 @@ import ( "fmt" "math/big" "os" + "path" "strings" "testing" "time" @@ -39,6 +40,7 @@ import ( // snapshotTestBasic wraps the common testing fields in the snapshot tests. type snapshotTestBasic struct { + scheme string // Disk scheme used for storing trie nodes chainBlocks int // Number of blocks to generate for the canonical chain snapshotBlock uint64 // Block number of the relevant snapshot disk layer commitBlock uint64 // Block number for which to commit the state to disk @@ -51,6 +53,7 @@ type snapshotTestBasic struct { // share fields, set in runtime datadir string + ancient string db ethdb.Database genDb ethdb.Database engine consensus.Engine @@ -60,10 +63,12 @@ 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") db, err := rawdb.Open(rawdb.OpenOptions{ Directory: datadir, - AncientsDirectory: datadir, + AncientsDirectory: ancient, + Ephemeral: true, }) if err != nil { t.Fatalf("Failed to create persistent database: %v", err) @@ -75,13 +80,8 @@ func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Blo Config: params.AllEthashProtocolChanges, } engine = ethash.NewFullFaker() - - // Snapshot is enabled, the first snapshot is created from the Genesis. - // The snapshot memory allowance is 256MB, it means no snapshot flush - // will happen during the block insertion. - cacheConfig = defaultCacheConfig ) - chain, err := NewBlockChain(db, cacheConfig, gspec, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(db, DefaultCacheConfigWithScheme(basic.scheme), gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("Failed to create chain: %v", err) } @@ -102,7 +102,7 @@ func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Blo startPoint = point if basic.commitBlock > 0 && basic.commitBlock == point { - chain.stateCache.TrieDB().Commit(blocks[point-1].Root(), false) + chain.TrieDB().Commit(blocks[point-1].Root(), false) } if basic.snapshotBlock > 0 && basic.snapshotBlock == point { // Flushing the entire snap tree into the disk, the @@ -121,6 +121,7 @@ func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Blo // Set runtime fields basic.datadir = datadir + basic.ancient = ancient basic.db = db basic.genDb = genDb basic.engine = engine @@ -210,6 +211,7 @@ func (basic *snapshotTestBasic) teardown() { basic.db.Close() basic.genDb.Close() os.RemoveAll(basic.datadir) + os.RemoveAll(basic.ancient) } // snapshotTest is a test case type for normal snapshot recovery. @@ -226,7 +228,7 @@ func (snaptest *snapshotTest) test(t *testing.T) { // Restart the chain normally chain.Stop() - newchain, err := NewBlockChain(snaptest.db, nil, 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, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } @@ -235,7 +237,7 @@ func (snaptest *snapshotTest) test(t *testing.T) { snaptest.verify(t, newchain, blocks) } -// crashSnapshotTest is a test case type for innormal snapshot recovery. +// crashSnapshotTest is a test case type for irregular snapshot recovery. // It can be used for testing that restart Geth after the crash. type crashSnapshotTest struct { snapshotTestBasic @@ -251,13 +253,14 @@ func (snaptest *crashSnapshotTest) test(t *testing.T) { db := chain.db db.Close() chain.stopWithoutSaving() + chain.triedb.Close() // Start a new blockchain back up and see where the repair leads us newdb, err := rawdb.Open(rawdb.OpenOptions{ Directory: snaptest.datadir, - AncientsDirectory: snaptest.datadir, + AncientsDirectory: snaptest.ancient, + Ephemeral: true, }) - if err != nil { t.Fatalf("Failed to reopen persistent database: %v", err) } @@ -267,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, nil, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) + newchain, err := NewBlockChain(newdb, DefaultCacheConfigWithScheme(snaptest.scheme), snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } newchain.Stop() - newchain, err = NewBlockChain(newdb, nil, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) + newchain, err = NewBlockChain(newdb, DefaultCacheConfigWithScheme(snaptest.scheme), snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } @@ -300,7 +303,7 @@ func (snaptest *gappedSnapshotTest) test(t *testing.T) { // Insert blocks without enabling snapshot if gapping is required. chain.Stop() - gappedBlocks, _ := GenerateChain(params.TestChainConfig, blocks[len(blocks)-1], snaptest.engine, snaptest.genDb, snaptest.gapped, func(i int, b *BlockGen) {}) + gappedBlocks, _ := GenerateChain(snaptest.gspec.Config, blocks[len(blocks)-1], snaptest.engine, snaptest.genDb, snaptest.gapped, func(i int, b *BlockGen) {}) // Insert a few more blocks without enabling snapshot var cacheConfig = &CacheConfig{ @@ -308,6 +311,7 @@ func (snaptest *gappedSnapshotTest) test(t *testing.T) { TrieDirtyLimit: 256, TrieTimeLimit: 5 * time.Minute, SnapshotLimit: 0, + StateScheme: snaptest.scheme, } newchain, err := NewBlockChain(snaptest.db, cacheConfig, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) if err != nil { @@ -317,7 +321,7 @@ func (snaptest *gappedSnapshotTest) test(t *testing.T) { newchain.Stop() // Restart the chain with enabling the snapshot - newchain, err = NewBlockChain(snaptest.db, nil, 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, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } @@ -345,7 +349,7 @@ func (snaptest *setHeadSnapshotTest) test(t *testing.T) { chain.SetHead(snaptest.setHead) chain.Stop() - newchain, err := NewBlockChain(snaptest.db, nil, 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, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } @@ -379,22 +383,24 @@ func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) { TrieDirtyLimit: 256, TrieTimeLimit: 5 * time.Minute, SnapshotLimit: 0, + StateScheme: snaptest.scheme, } newchain, err := NewBlockChain(snaptest.db, config, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } - newBlocks, _ := GenerateChain(params.TestChainConfig, blocks[len(blocks)-1], snaptest.engine, snaptest.genDb, snaptest.newBlocks, func(i int, b *BlockGen) {}) + newBlocks, _ := GenerateChain(snaptest.gspec.Config, blocks[len(blocks)-1], snaptest.engine, snaptest.genDb, snaptest.newBlocks, func(i int, b *BlockGen) {}) newchain.InsertChain(newBlocks) newchain.Stop() - // Restart the chain, the wiper should starts working + // Restart the chain, the wiper should start working config = &CacheConfig{ TrieCleanLimit: 256, TrieDirtyLimit: 256, TrieTimeLimit: 5 * time.Minute, SnapshotLimit: 256, SnapshotWait: false, // Don't wait rebuild + StateScheme: snaptest.scheme, } tmp, err := NewBlockChain(snaptest.db, config, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) if err != nil { @@ -402,14 +408,15 @@ func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) { } // Simulate the blockchain crash. + tmp.triedb.Close() tmp.stopWithoutSaving() - newchain, err = NewBlockChain(snaptest.db, nil, 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, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } - defer newchain.Stop() snaptest.verify(t, newchain, blocks) + newchain.Stop() } // Tests a Geth restart with valid snapshot. Before the shutdown, all snapshot @@ -433,20 +440,23 @@ func TestRestartWithNewSnapshot(t *testing.T) { // Expected head fast block: C8 // Expected head block : C8 // Expected snapshot disk : G - test := &snapshotTest{ - snapshotTestBasic{ - chainBlocks: 8, - snapshotBlock: 0, - commitBlock: 0, - expCanonicalBlocks: 8, - expHeadHeader: 8, - expHeadFastBlock: 8, - expHeadBlock: 8, - expSnapshotBottom: 0, // Initial disk layer built from genesis - }, + for _, scheme := range []string{rawdb.HashScheme, rawdb.PathScheme} { + test := &snapshotTest{ + snapshotTestBasic{ + scheme: scheme, + chainBlocks: 8, + snapshotBlock: 0, + commitBlock: 0, + expCanonicalBlocks: 8, + expHeadHeader: 8, + expHeadFastBlock: 8, + expHeadBlock: 8, + expSnapshotBottom: 0, // Initial disk layer built from genesis + }, + } + test.test(t) + test.teardown() } - test.test(t) - test.teardown() } // Tests a Geth was crashed and restarts with a broken snapshot. In this case the @@ -472,20 +482,23 @@ func TestNoCommitCrashWithNewSnapshot(t *testing.T) { // Expected head fast block: C8 // Expected head block : G // Expected snapshot disk : C4 - test := &crashSnapshotTest{ - snapshotTestBasic{ - chainBlocks: 8, - snapshotBlock: 4, - commitBlock: 0, - expCanonicalBlocks: 8, - expHeadHeader: 8, - expHeadFastBlock: 8, - expHeadBlock: 0, - expSnapshotBottom: 4, // Last committed disk layer, wait recovery - }, + for _, scheme := range []string{rawdb.HashScheme, rawdb.PathScheme} { + test := &crashSnapshotTest{ + snapshotTestBasic{ + scheme: scheme, + chainBlocks: 8, + snapshotBlock: 4, + commitBlock: 0, + expCanonicalBlocks: 8, + expHeadHeader: 8, + expHeadFastBlock: 8, + expHeadBlock: 0, + expSnapshotBottom: 4, // Last committed disk layer, wait recovery + }, + } + test.test(t) + test.teardown() } - test.test(t) - test.teardown() } // Tests a Geth was crashed and restarts with a broken snapshot. In this case the @@ -511,20 +524,23 @@ func TestLowCommitCrashWithNewSnapshot(t *testing.T) { // Expected head fast block: C8 // Expected head block : C2 // Expected snapshot disk : C4 - test := &crashSnapshotTest{ - snapshotTestBasic{ - chainBlocks: 8, - snapshotBlock: 4, - commitBlock: 2, - expCanonicalBlocks: 8, - expHeadHeader: 8, - expHeadFastBlock: 8, - expHeadBlock: 2, - expSnapshotBottom: 4, // Last committed disk layer, wait recovery - }, + for _, scheme := range []string{rawdb.HashScheme, rawdb.PathScheme} { + test := &crashSnapshotTest{ + snapshotTestBasic{ + scheme: scheme, + chainBlocks: 8, + snapshotBlock: 4, + commitBlock: 2, + expCanonicalBlocks: 8, + expHeadHeader: 8, + expHeadFastBlock: 8, + expHeadBlock: 2, + expSnapshotBottom: 4, // Last committed disk layer, wait recovery + }, + } + test.test(t) + test.teardown() } - test.test(t) - test.teardown() } // Tests a Geth was crashed and restarts with a broken snapshot. In this case @@ -550,20 +566,27 @@ func TestHighCommitCrashWithNewSnapshot(t *testing.T) { // Expected head fast block: C8 // Expected head block : G // Expected snapshot disk : C4 - test := &crashSnapshotTest{ - snapshotTestBasic{ - chainBlocks: 8, - snapshotBlock: 4, - commitBlock: 6, - expCanonicalBlocks: 8, - expHeadHeader: 8, - expHeadFastBlock: 8, - expHeadBlock: 0, - expSnapshotBottom: 4, // Last committed disk layer, wait recovery - }, + for _, scheme := range []string{rawdb.HashScheme, rawdb.PathScheme} { + expHead := uint64(0) + if scheme == rawdb.PathScheme { + expHead = uint64(4) + } + test := &crashSnapshotTest{ + snapshotTestBasic{ + scheme: scheme, + chainBlocks: 8, + snapshotBlock: 4, + commitBlock: 6, + expCanonicalBlocks: 8, + expHeadHeader: 8, + expHeadFastBlock: 8, + expHeadBlock: expHead, + expSnapshotBottom: 4, // Last committed disk layer, wait recovery + }, + } + test.test(t) + test.teardown() } - test.test(t) - test.teardown() } // Tests a Geth was running with snapshot enabled. Then restarts without @@ -587,21 +610,24 @@ func TestGappedNewSnapshot(t *testing.T) { // Expected head fast block: C10 // Expected head block : C10 // Expected snapshot disk : C10 - test := &gappedSnapshotTest{ - snapshotTestBasic: snapshotTestBasic{ - chainBlocks: 8, - snapshotBlock: 0, - commitBlock: 0, - expCanonicalBlocks: 10, - expHeadHeader: 10, - expHeadFastBlock: 10, - expHeadBlock: 10, - expSnapshotBottom: 10, // Rebuilt snapshot from the latest HEAD - }, - gapped: 2, + for _, scheme := range []string{rawdb.HashScheme, rawdb.PathScheme} { + test := &gappedSnapshotTest{ + snapshotTestBasic: snapshotTestBasic{ + scheme: scheme, + chainBlocks: 8, + snapshotBlock: 0, + commitBlock: 0, + expCanonicalBlocks: 10, + expHeadHeader: 10, + expHeadFastBlock: 10, + expHeadBlock: 10, + expSnapshotBottom: 10, // Rebuilt snapshot from the latest HEAD + }, + gapped: 2, + } + test.test(t) + test.teardown() } - test.test(t) - test.teardown() } // Tests the Geth was running with snapshot enabled and resetHead is applied. @@ -625,21 +651,24 @@ func TestSetHeadWithNewSnapshot(t *testing.T) { // Expected head fast block: C4 // Expected head block : C4 // Expected snapshot disk : G - test := &setHeadSnapshotTest{ - snapshotTestBasic: snapshotTestBasic{ - chainBlocks: 8, - snapshotBlock: 0, - commitBlock: 0, - expCanonicalBlocks: 4, - expHeadHeader: 4, - expHeadFastBlock: 4, - expHeadBlock: 4, - expSnapshotBottom: 0, // The initial disk layer is built from the genesis - }, - setHead: 4, + for _, scheme := range []string{rawdb.HashScheme, rawdb.PathScheme} { + test := &setHeadSnapshotTest{ + snapshotTestBasic: snapshotTestBasic{ + scheme: scheme, + chainBlocks: 8, + snapshotBlock: 0, + commitBlock: 0, + expCanonicalBlocks: 4, + expHeadHeader: 4, + expHeadFastBlock: 4, + expHeadBlock: 4, + expSnapshotBottom: 0, // The initial disk layer is built from the genesis + }, + setHead: 4, + } + test.test(t) + test.teardown() } - test.test(t) - test.teardown() } // Tests the Geth was running with a complete snapshot and then imports a few @@ -663,19 +692,22 @@ func TestRecoverSnapshotFromWipingCrash(t *testing.T) { // Expected head fast block: C10 // Expected head block : C8 // Expected snapshot disk : C10 - test := &wipeCrashSnapshotTest{ - snapshotTestBasic: snapshotTestBasic{ - chainBlocks: 8, - snapshotBlock: 4, - commitBlock: 0, - expCanonicalBlocks: 10, - expHeadHeader: 10, - expHeadFastBlock: 10, - expHeadBlock: 10, - expSnapshotBottom: 10, - }, - newBlocks: 2, + for _, scheme := range []string{rawdb.HashScheme, rawdb.PathScheme} { + test := &wipeCrashSnapshotTest{ + snapshotTestBasic: snapshotTestBasic{ + scheme: scheme, + chainBlocks: 8, + snapshotBlock: 4, + commitBlock: 0, + expCanonicalBlocks: 10, + expHeadHeader: 10, + expHeadFastBlock: 10, + expHeadBlock: 10, + expSnapshotBottom: 10, + }, + newBlocks: 2, + } + test.test(t) + test.teardown() } - test.test(t) - test.teardown() } diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 5ec685c99f..992f8d168f 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -52,7 +52,7 @@ var ( // chain. Depending on the full flag, if creates either a full block chain or a // header only chain. The database and genesis specification for block generation // are also returned in case more test blocks are needed later. -func newCanonical(engine consensus.Engine, n int, full bool) (ethdb.Database, *Genesis, *BlockChain, error) { +func newCanonical(engine consensus.Engine, n int, full bool, scheme string) (ethdb.Database, *Genesis, *BlockChain, error) { var ( genesis = &Genesis{ BaseFee: big.NewInt(params.InitialBaseFee), @@ -60,7 +60,7 @@ func newCanonical(engine consensus.Engine, n int, full bool) (ethdb.Database, *G } ) // Initialize a fresh chain with only a genesis block - blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, genesis, nil, engine, vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil) // Create and inject the requested chain if n == 0 { @@ -83,9 +83,9 @@ func newGwei(n int64) *big.Int { } // Test fork of length N starting from block i -func testFork(t *testing.T, blockchain *BlockChain, i, n int, full bool, comparator func(td1, td2 *big.Int)) { +func testFork(t *testing.T, blockchain *BlockChain, i, n int, full bool, comparator func(td1, td2 *big.Int), scheme string) { // Copy old chain up to #i into a new db - genDb, _, blockchain2, err := newCanonical(ethash.NewFaker(), i, full) + genDb, _, blockchain2, err := newCanonical(ethash.NewFaker(), i, full, scheme) if err != nil { t.Fatal("could not make new canonical in testFork", err) } @@ -176,7 +176,7 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error { blockchain.chainmu.MustLock() rawdb.WriteTd(blockchain.db, block.Hash(), block.NumberU64(), new(big.Int).Add(block.Difficulty(), blockchain.GetTd(block.ParentHash(), block.NumberU64()-1))) rawdb.WriteBlock(blockchain.db, block) - statedb.Commit(false) + statedb.Commit(block.NumberU64(), false) blockchain.chainmu.Unlock() } return nil @@ -198,9 +198,13 @@ func testHeaderChainImport(chain []*types.Header, blockchain *BlockChain) error } return nil } - func TestLastBlock(t *testing.T) { - genDb, _, blockchain, err := newCanonical(ethash.NewFaker(), 0, true) + testLastBlock(t, rawdb.HashScheme) + testLastBlock(t, rawdb.PathScheme) +} + +func testLastBlock(t *testing.T, scheme string) { + genDb, _, blockchain, err := newCanonical(ethash.NewFaker(), 0, true, scheme) if err != nil { t.Fatalf("failed to create pristine chain: %v", err) } @@ -217,9 +221,9 @@ func TestLastBlock(t *testing.T) { // Test inserts the blocks/headers after the fork choice rule is changed. // The chain is reorged to whatever specified. -func testInsertAfterMerge(t *testing.T, blockchain *BlockChain, i, n int, full bool) { +func testInsertAfterMerge(t *testing.T, blockchain *BlockChain, i, n int, full bool, scheme string) { // Copy old chain up to #i into a new db - genDb, _, blockchain2, err := newCanonical(ethash.NewFaker(), i, full) + genDb, _, blockchain2, err := newCanonical(ethash.NewFaker(), i, full, scheme) if err != nil { t.Fatal("could not make new canonical in testFork", err) } @@ -266,14 +270,20 @@ func testInsertAfterMerge(t *testing.T, blockchain *BlockChain, i, n int, full b // Tests that given a starting canonical chain of a given size, it can be extended // with various length chains. -func TestExtendCanonicalHeaders(t *testing.T) { testExtendCanonical(t, false) } -func TestExtendCanonicalBlocks(t *testing.T) { testExtendCanonical(t, true) } +func TestExtendCanonicalHeaders(t *testing.T) { + testExtendCanonical(t, false, rawdb.HashScheme) + testExtendCanonical(t, false, rawdb.PathScheme) +} +func TestExtendCanonicalBlocks(t *testing.T) { + testExtendCanonical(t, true, rawdb.HashScheme) + testExtendCanonical(t, true, rawdb.PathScheme) +} -func testExtendCanonical(t *testing.T, full bool) { +func testExtendCanonical(t *testing.T, full bool, scheme string) { length := 5 // Make first chain starting from genesis - _, _, processor, err := newCanonical(ethash.NewFaker(), length, full) + _, _, processor, err := newCanonical(ethash.NewFaker(), length, full, scheme) if err != nil { t.Fatalf("failed to make new canonical chain: %v", err) } @@ -286,41 +296,53 @@ func testExtendCanonical(t *testing.T, full bool) { } } // Start fork from current height - testFork(t, processor, length, 1, full, better) - testFork(t, processor, length, 2, full, better) - testFork(t, processor, length, 5, full, better) - testFork(t, processor, length, 10, full, better) + testFork(t, processor, length, 1, full, better, scheme) + testFork(t, processor, length, 2, full, better, scheme) + testFork(t, processor, length, 5, full, better, scheme) + testFork(t, processor, length, 10, full, better, scheme) } // Tests that given a starting canonical chain of a given size, it can be extended // with various length chains. -func TestExtendCanonicalHeadersAfterMerge(t *testing.T) { testExtendCanonicalAfterMerge(t, false) } -func TestExtendCanonicalBlocksAfterMerge(t *testing.T) { testExtendCanonicalAfterMerge(t, true) } +func TestExtendCanonicalHeadersAfterMerge(t *testing.T) { + testExtendCanonicalAfterMerge(t, false, rawdb.HashScheme) + testExtendCanonicalAfterMerge(t, false, rawdb.PathScheme) +} +func TestExtendCanonicalBlocksAfterMerge(t *testing.T) { + testExtendCanonicalAfterMerge(t, true, rawdb.HashScheme) + testExtendCanonicalAfterMerge(t, true, rawdb.PathScheme) +} -func testExtendCanonicalAfterMerge(t *testing.T, full bool) { +func testExtendCanonicalAfterMerge(t *testing.T, full bool, scheme string) { length := 5 // Make first chain starting from genesis - _, _, processor, err := newCanonical(ethash.NewFaker(), length, full) + _, _, processor, err := newCanonical(ethash.NewFaker(), length, full, scheme) if err != nil { t.Fatalf("failed to make new canonical chain: %v", err) } defer processor.Stop() - testInsertAfterMerge(t, processor, length, 1, full) - testInsertAfterMerge(t, processor, length, 10, full) + testInsertAfterMerge(t, processor, length, 1, full, scheme) + testInsertAfterMerge(t, processor, length, 10, full, scheme) } // Tests that given a starting canonical chain of a given size, creating shorter // forks do not take canonical ownership. -func TestShorterForkHeaders(t *testing.T) { testShorterFork(t, false) } -func TestShorterForkBlocks(t *testing.T) { testShorterFork(t, true) } +func TestShorterForkHeaders(t *testing.T) { + testShorterFork(t, false, rawdb.HashScheme) + testShorterFork(t, false, rawdb.PathScheme) +} +func TestShorterForkBlocks(t *testing.T) { + testShorterFork(t, true, rawdb.HashScheme) + testShorterFork(t, true, rawdb.PathScheme) +} -func testShorterFork(t *testing.T, full bool) { +func testShorterFork(t *testing.T, full bool, scheme string) { length := 10 // Make first chain starting from genesis - _, _, processor, err := newCanonical(ethash.NewFaker(), length, full) + _, _, processor, err := newCanonical(ethash.NewFaker(), length, full, scheme) if err != nil { t.Fatalf("failed to make new canonical chain: %v", err) } @@ -333,93 +355,117 @@ func testShorterFork(t *testing.T, full bool) { } } // Sum of numbers must be less than `length` for this to be a shorter fork - testFork(t, processor, 0, 3, full, worse) - testFork(t, processor, 0, 7, full, worse) - testFork(t, processor, 1, 1, full, worse) - testFork(t, processor, 1, 7, full, worse) - testFork(t, processor, 5, 3, full, worse) - testFork(t, processor, 5, 4, full, worse) + testFork(t, processor, 0, 3, full, worse, scheme) + testFork(t, processor, 0, 7, full, worse, scheme) + testFork(t, processor, 1, 1, full, worse, scheme) + testFork(t, processor, 1, 7, full, worse, scheme) + testFork(t, processor, 5, 3, full, worse, scheme) + testFork(t, processor, 5, 4, full, worse, scheme) } // Tests that given a starting canonical chain of a given size, creating shorter // forks do not take canonical ownership. -func TestShorterForkHeadersAfterMerge(t *testing.T) { testShorterForkAfterMerge(t, false) } -func TestShorterForkBlocksAfterMerge(t *testing.T) { testShorterForkAfterMerge(t, true) } +func TestShorterForkHeadersAfterMerge(t *testing.T) { + testShorterForkAfterMerge(t, false, rawdb.HashScheme) + testShorterForkAfterMerge(t, false, rawdb.PathScheme) +} +func TestShorterForkBlocksAfterMerge(t *testing.T) { + testShorterForkAfterMerge(t, true, rawdb.HashScheme) + testShorterForkAfterMerge(t, true, rawdb.PathScheme) +} -func testShorterForkAfterMerge(t *testing.T, full bool) { +func testShorterForkAfterMerge(t *testing.T, full bool, scheme string) { length := 10 // Make first chain starting from genesis - _, _, processor, err := newCanonical(ethash.NewFaker(), length, full) + _, _, processor, err := newCanonical(ethash.NewFaker(), length, full, scheme) if err != nil { t.Fatalf("failed to make new canonical chain: %v", err) } defer processor.Stop() - testInsertAfterMerge(t, processor, 0, 3, full) - testInsertAfterMerge(t, processor, 0, 7, full) - testInsertAfterMerge(t, processor, 1, 1, full) - testInsertAfterMerge(t, processor, 1, 7, full) - testInsertAfterMerge(t, processor, 5, 3, full) - testInsertAfterMerge(t, processor, 5, 4, full) + testInsertAfterMerge(t, processor, 0, 3, full, scheme) + testInsertAfterMerge(t, processor, 0, 7, full, scheme) + testInsertAfterMerge(t, processor, 1, 1, full, scheme) + testInsertAfterMerge(t, processor, 1, 7, full, scheme) + testInsertAfterMerge(t, processor, 5, 3, full, scheme) + testInsertAfterMerge(t, processor, 5, 4, full, scheme) } // Tests that given a starting canonical chain of a given size, creating longer // forks do take canonical ownership. -func TestLongerForkHeaders(t *testing.T) { testLongerFork(t, false) } -func TestLongerForkBlocks(t *testing.T) { testLongerFork(t, true) } +func TestLongerForkHeaders(t *testing.T) { + testLongerFork(t, false, rawdb.HashScheme) + testLongerFork(t, false, rawdb.PathScheme) +} +func TestLongerForkBlocks(t *testing.T) { + testLongerFork(t, true, rawdb.HashScheme) + testLongerFork(t, true, rawdb.PathScheme) +} -func testLongerFork(t *testing.T, full bool) { +func testLongerFork(t *testing.T, full bool, scheme string) { length := 10 // Make first chain starting from genesis - _, _, processor, err := newCanonical(ethash.NewFaker(), length, full) + _, _, processor, err := newCanonical(ethash.NewFaker(), length, full, scheme) if err != nil { t.Fatalf("failed to make new canonical chain: %v", err) } defer processor.Stop() - testInsertAfterMerge(t, processor, 0, 11, full) - testInsertAfterMerge(t, processor, 0, 15, full) - testInsertAfterMerge(t, processor, 1, 10, full) - testInsertAfterMerge(t, processor, 1, 12, full) - testInsertAfterMerge(t, processor, 5, 6, full) - testInsertAfterMerge(t, processor, 5, 8, full) + testInsertAfterMerge(t, processor, 0, 11, full, scheme) + testInsertAfterMerge(t, processor, 0, 15, full, scheme) + testInsertAfterMerge(t, processor, 1, 10, full, scheme) + testInsertAfterMerge(t, processor, 1, 12, full, scheme) + testInsertAfterMerge(t, processor, 5, 6, full, scheme) + testInsertAfterMerge(t, processor, 5, 8, full, scheme) } // Tests that given a starting canonical chain of a given size, creating longer // forks do take canonical ownership. -func TestLongerForkHeadersAfterMerge(t *testing.T) { testLongerForkAfterMerge(t, false) } -func TestLongerForkBlocksAfterMerge(t *testing.T) { testLongerForkAfterMerge(t, true) } +func TestLongerForkHeadersAfterMerge(t *testing.T) { + testLongerForkAfterMerge(t, false, rawdb.HashScheme) + testLongerForkAfterMerge(t, false, rawdb.PathScheme) +} +func TestLongerForkBlocksAfterMerge(t *testing.T) { + testLongerForkAfterMerge(t, true, rawdb.HashScheme) + testLongerForkAfterMerge(t, true, rawdb.PathScheme) +} -func testLongerForkAfterMerge(t *testing.T, full bool) { +func testLongerForkAfterMerge(t *testing.T, full bool, scheme string) { length := 10 // Make first chain starting from genesis - _, _, processor, err := newCanonical(ethash.NewFaker(), length, full) + _, _, processor, err := newCanonical(ethash.NewFaker(), length, full, scheme) if err != nil { t.Fatalf("failed to make new canonical chain: %v", err) } defer processor.Stop() - testInsertAfterMerge(t, processor, 0, 11, full) - testInsertAfterMerge(t, processor, 0, 15, full) - testInsertAfterMerge(t, processor, 1, 10, full) - testInsertAfterMerge(t, processor, 1, 12, full) - testInsertAfterMerge(t, processor, 5, 6, full) - testInsertAfterMerge(t, processor, 5, 8, full) + testInsertAfterMerge(t, processor, 0, 11, full, scheme) + testInsertAfterMerge(t, processor, 0, 15, full, scheme) + testInsertAfterMerge(t, processor, 1, 10, full, scheme) + testInsertAfterMerge(t, processor, 1, 12, full, scheme) + testInsertAfterMerge(t, processor, 5, 6, full, scheme) + testInsertAfterMerge(t, processor, 5, 8, full, scheme) } // Tests that given a starting canonical chain of a given size, creating equal // forks do take canonical ownership. -func TestEqualForkHeaders(t *testing.T) { testEqualFork(t, false) } -func TestEqualForkBlocks(t *testing.T) { testEqualFork(t, true) } +func TestEqualForkHeaders(t *testing.T) { + testEqualFork(t, false, rawdb.HashScheme) + testEqualFork(t, false, rawdb.PathScheme) +} +func TestEqualForkBlocks(t *testing.T) { + testEqualFork(t, true, rawdb.HashScheme) + testEqualFork(t, true, rawdb.PathScheme) +} -func testEqualFork(t *testing.T, full bool) { +func testEqualFork(t *testing.T, full bool, scheme string) { length := 10 // Make first chain starting from genesis - _, _, processor, err := newCanonical(ethash.NewFaker(), length, full) + _, _, processor, err := newCanonical(ethash.NewFaker(), length, full, scheme) if err != nil { t.Fatalf("failed to make new canonical chain: %v", err) } @@ -432,44 +478,56 @@ func testEqualFork(t *testing.T, full bool) { } } // Sum of numbers must be equal to `length` for this to be an equal fork - testFork(t, processor, 0, 10, full, equal) - testFork(t, processor, 1, 9, full, equal) - testFork(t, processor, 2, 8, full, equal) - testFork(t, processor, 5, 5, full, equal) - testFork(t, processor, 6, 4, full, equal) - testFork(t, processor, 9, 1, full, equal) + testFork(t, processor, 0, 10, full, equal, scheme) + testFork(t, processor, 1, 9, full, equal, scheme) + testFork(t, processor, 2, 8, full, equal, scheme) + testFork(t, processor, 5, 5, full, equal, scheme) + testFork(t, processor, 6, 4, full, equal, scheme) + testFork(t, processor, 9, 1, full, equal, scheme) } // Tests that given a starting canonical chain of a given size, creating equal // forks do take canonical ownership. -func TestEqualForkHeadersAfterMerge(t *testing.T) { testEqualForkAfterMerge(t, false) } -func TestEqualForkBlocksAfterMerge(t *testing.T) { testEqualForkAfterMerge(t, true) } +func TestEqualForkHeadersAfterMerge(t *testing.T) { + testEqualForkAfterMerge(t, false, rawdb.HashScheme) + testEqualForkAfterMerge(t, false, rawdb.PathScheme) +} +func TestEqualForkBlocksAfterMerge(t *testing.T) { + testEqualForkAfterMerge(t, true, rawdb.HashScheme) + testEqualForkAfterMerge(t, true, rawdb.PathScheme) +} -func testEqualForkAfterMerge(t *testing.T, full bool) { +func testEqualForkAfterMerge(t *testing.T, full bool, scheme string) { length := 10 // Make first chain starting from genesis - _, _, processor, err := newCanonical(ethash.NewFaker(), length, full) + _, _, processor, err := newCanonical(ethash.NewFaker(), length, full, scheme) if err != nil { t.Fatalf("failed to make new canonical chain: %v", err) } defer processor.Stop() - testInsertAfterMerge(t, processor, 0, 10, full) - testInsertAfterMerge(t, processor, 1, 9, full) - testInsertAfterMerge(t, processor, 2, 8, full) - testInsertAfterMerge(t, processor, 5, 5, full) - testInsertAfterMerge(t, processor, 6, 4, full) - testInsertAfterMerge(t, processor, 9, 1, full) + testInsertAfterMerge(t, processor, 0, 10, full, scheme) + testInsertAfterMerge(t, processor, 1, 9, full, scheme) + testInsertAfterMerge(t, processor, 2, 8, full, scheme) + testInsertAfterMerge(t, processor, 5, 5, full, scheme) + testInsertAfterMerge(t, processor, 6, 4, full, scheme) + testInsertAfterMerge(t, processor, 9, 1, full, scheme) } // Tests that chains missing links do not get accepted by the processor. -func TestBrokenHeaderChain(t *testing.T) { testBrokenChain(t, false) } -func TestBrokenBlockChain(t *testing.T) { testBrokenChain(t, true) } +func TestBrokenHeaderChain(t *testing.T) { + testBrokenChain(t, false, rawdb.HashScheme) + testBrokenChain(t, false, rawdb.PathScheme) +} +func TestBrokenBlockChain(t *testing.T) { + testBrokenChain(t, true, rawdb.HashScheme) + testBrokenChain(t, true, rawdb.PathScheme) +} -func testBrokenChain(t *testing.T, full bool) { +func testBrokenChain(t *testing.T, full bool, scheme string) { // Make chain starting from genesis - genDb, _, blockchain, err := newCanonical(ethash.NewFaker(), 10, full) + genDb, _, blockchain, err := newCanonical(ethash.NewFaker(), 10, full, scheme) if err != nil { t.Fatalf("failed to make new canonical chain: %v", err) } @@ -491,19 +549,31 @@ func testBrokenChain(t *testing.T, full bool) { // Tests that reorganising a long difficult chain after a short easy one // overwrites the canonical numbers and links in the database. -func TestReorgLongHeaders(t *testing.T) { testReorgLong(t, false) } -func TestReorgLongBlocks(t *testing.T) { testReorgLong(t, true) } +func TestReorgLongHeaders(t *testing.T) { + testReorgLong(t, false, rawdb.HashScheme) + testReorgLong(t, false, rawdb.PathScheme) +} +func TestReorgLongBlocks(t *testing.T) { + testReorgLong(t, true, rawdb.HashScheme) + testReorgLong(t, true, rawdb.PathScheme) +} -func testReorgLong(t *testing.T, full bool) { - testReorg(t, []int64{0, 0, -9}, []int64{0, 0, 0, -9}, 393280+params.GenesisDifficulty.Int64(), full) +func testReorgLong(t *testing.T, full bool, scheme string) { + testReorg(t, []int64{0, 0, -9}, []int64{0, 0, 0, -9}, 393280+params.GenesisDifficulty.Int64(), full, scheme) } // Tests that reorganising a short difficult chain after a long easy one // overwrites the canonical numbers and links in the database. -func TestReorgShortHeaders(t *testing.T) { testReorgShort(t, false) } -func TestReorgShortBlocks(t *testing.T) { testReorgShort(t, true) } +func TestReorgShortHeaders(t *testing.T) { + testReorgShort(t, false, rawdb.HashScheme) + testReorgShort(t, false, rawdb.PathScheme) +} +func TestReorgShortBlocks(t *testing.T) { + testReorgShort(t, true, rawdb.HashScheme) + testReorgShort(t, true, rawdb.PathScheme) +} -func testReorgShort(t *testing.T, full bool) { +func testReorgShort(t *testing.T, full bool, scheme string) { // Create a long easy chain vs. a short heavy one. Due to difficulty adjustment // we need a fairly long chain of blocks with different difficulties for a short // one to become heavier than a long one. The 96 is an empirical value. @@ -515,12 +585,12 @@ func testReorgShort(t *testing.T, full bool) { for i := 0; i < len(diff); i++ { diff[i] = -9 } - testReorg(t, easy, diff, 12615120+params.GenesisDifficulty.Int64(), full) + testReorg(t, easy, diff, 12615120+params.GenesisDifficulty.Int64(), full, scheme) } -func testReorg(t *testing.T, first, second []int64, td int64, full bool) { +func testReorg(t *testing.T, first, second []int64, td int64, full bool, scheme string) { // Create a pristine chain and database - genDb, _, blockchain, err := newCanonical(ethash.NewFaker(), 0, full) + genDb, _, blockchain, err := newCanonical(ethash.NewFaker(), 0, full, scheme) if err != nil { t.Fatalf("failed to create pristine chain: %v", err) } @@ -588,12 +658,18 @@ func testReorg(t *testing.T, first, second []int64, td int64, full bool) { } // Tests that the insertion functions detect banned hashes. -func TestBadHeaderHashes(t *testing.T) { testBadHashes(t, false) } -func TestBadBlockHashes(t *testing.T) { testBadHashes(t, true) } +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) { +func testBadHashes(t *testing.T, full bool, scheme string) { // Create a pristine chain and database - genDb, _, blockchain, err := newCanonical(ethash.NewFaker(), 0, full) + genDb, _, blockchain, err := newCanonical(ethash.NewFaker(), 0, full, scheme) if err != nil { t.Fatalf("failed to create pristine chain: %v", err) } @@ -622,12 +698,18 @@ func testBadHashes(t *testing.T, full bool) { // 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) } -func TestReorgBadBlockHashes(t *testing.T) { testReorgBadHashes(t, true) } +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) { +func testReorgBadHashes(t *testing.T, full bool, scheme string) { // Create a pristine chain and database - genDb, gspec, blockchain, err := newCanonical(ethash.NewFaker(), 0, full) + genDb, gspec, blockchain, err := newCanonical(ethash.NewFaker(), 0, full, scheme) if err != nil { t.Fatalf("failed to create pristine chain: %v", err) } @@ -657,7 +739,7 @@ func testReorgBadHashes(t *testing.T, full bool) { blockchain.Stop() // Create a new BlockChain and check that it rolled back the state. - ncm, err := NewBlockChain(blockchain.db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + 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) } @@ -677,13 +759,19 @@ func testReorgBadHashes(t *testing.T, full bool) { } // Tests chain insertions in the face of one entity containing an invalid nonce. -func TestHeadersInsertNonceError(t *testing.T) { testInsertNonceError(t, false) } -func TestBlocksInsertNonceError(t *testing.T) { testInsertNonceError(t, true) } +func TestHeadersInsertNonceError(t *testing.T) { + testInsertNonceError(t, false, rawdb.HashScheme) + testInsertNonceError(t, false, rawdb.PathScheme) +} +func TestBlocksInsertNonceError(t *testing.T) { + testInsertNonceError(t, true, rawdb.HashScheme) + testInsertNonceError(t, true, rawdb.PathScheme) +} -func testInsertNonceError(t *testing.T, full bool) { +func testInsertNonceError(t *testing.T, full bool, scheme string) { doTest := func(i int) { // Create a pristine chain and database - genDb, _, blockchain, err := newCanonical(ethash.NewFaker(), 0, full) + genDb, _, blockchain, err := newCanonical(ethash.NewFaker(), 0, full, scheme) if err != nil { t.Fatalf("failed to create pristine chain: %v", err) } @@ -738,6 +826,11 @@ func testInsertNonceError(t *testing.T, full bool) { // Tests that fast importing a block chain produces the same chain data as the // classical full block processing. func TestFastVsFullChains(t *testing.T) { + testFastVsFullChains(t, rawdb.HashScheme) + testFastVsFullChains(t, rawdb.PathScheme) +} + +func testFastVsFullChains(t *testing.T, scheme string) { // Configure and generate a sample block chain var ( key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") @@ -770,7 +863,7 @@ func TestFastVsFullChains(t *testing.T) { }) // Import the chain as an archive node for the comparison baseline archiveDb := rawdb.NewMemoryDatabase() - archive, _ := NewBlockChain(archiveDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + archive, _ := NewBlockChain(archiveDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer archive.Stop() if n, err := archive.InsertChain(blocks); err != nil { @@ -778,7 +871,7 @@ func TestFastVsFullChains(t *testing.T) { } // Fast import the chain as a non-archive node to test fastDb := rawdb.NewMemoryDatabase() - fast, _ := NewBlockChain(fastDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + fast, _ := NewBlockChain(fastDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer fast.Stop() headers := make([]*types.Header, len(blocks)) @@ -797,7 +890,8 @@ func TestFastVsFullChains(t *testing.T) { t.Fatalf("failed to create temp freezer db: %v", err) } defer ancientDb.Close() - ancient, _ := NewBlockChain(ancientDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + + ancient, _ := NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer ancient.Stop() if n, err := ancient.InsertHeaderChain(headers); err != nil { @@ -865,6 +959,11 @@ func TestFastVsFullChains(t *testing.T) { // Tests that various import methods move the chain head pointers to the correct // positions. func TestLightVsFastVsFullChainHeads(t *testing.T) { + testLightVsFastVsFullChainHeads(t, rawdb.HashScheme) + testLightVsFastVsFullChainHeads(t, rawdb.PathScheme) +} + +func testLightVsFastVsFullChainHeads(t *testing.T, scheme string) { // Configure and generate a sample block chain var ( key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") @@ -910,6 +1009,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { archiveCaching := *defaultCacheConfig archiveCaching.TrieDirtyDisabled = true + archiveCaching.StateScheme = scheme archive, _ := NewBlockChain(archiveDb, &archiveCaching, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) if n, err := archive.InsertChain(blocks); err != nil { @@ -924,7 +1024,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { // Import the chain as a non-archive node and ensure all pointers are updated fastDb := makeDb() defer fastDb.Close() - fast, _ := NewBlockChain(fastDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + fast, _ := NewBlockChain(fastDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer fast.Stop() headers := make([]*types.Header, len(blocks)) @@ -944,7 +1044,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { // Import the chain as a ancient-first node and ensure all pointers are updated ancientDb := makeDb() defer ancientDb.Close() - ancient, _ := NewBlockChain(ancientDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + ancient, _ := NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer ancient.Stop() if n, err := ancient.InsertHeaderChain(headers); err != nil { @@ -963,7 +1063,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { // Import the chain as a light node and ensure all pointers are updated lightDb := makeDb() defer lightDb.Close() - light, _ := NewBlockChain(lightDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + light, _ := NewBlockChain(lightDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) if n, err := light.InsertHeaderChain(headers); err != nil { t.Fatalf("failed to insert header %d: %v", n, err) } @@ -976,6 +1076,11 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { // Tests that chain reorganisations handle transaction removals and reinsertions. func TestChainTxReorgs(t *testing.T) { + testChainTxReorgs(t, rawdb.HashScheme) + testChainTxReorgs(t, rawdb.PathScheme) +} + +func testChainTxReorgs(t *testing.T, scheme string) { var ( key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") @@ -1031,7 +1136,7 @@ func TestChainTxReorgs(t *testing.T) { }) // Import the chain. This runs all block validation rules. db := rawdb.NewMemoryDatabase() - blockchain, _ := NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) if i, err := blockchain.InsertChain(chain); err != nil { t.Fatalf("failed to insert original chain[%d]: %v", i, err) } @@ -1090,6 +1195,11 @@ func TestChainTxReorgs(t *testing.T) { } func TestLogReorgs(t *testing.T) { + testLogReorgs(t, rawdb.HashScheme) + testLogReorgs(t, rawdb.PathScheme) +} + +func testLogReorgs(t *testing.T, scheme string) { var ( key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") addr1 = crypto.PubkeyToAddress(key1.PublicKey) @@ -1100,7 +1210,7 @@ func TestLogReorgs(t *testing.T) { signer = types.LatestSigner(gspec.Config) ) - blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer blockchain.Stop() rmLogsCh := make(chan RemovedLogsEvent) @@ -1145,13 +1255,18 @@ var logCode = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd // This test checks that log events and RemovedLogsEvent are sent // when the chain reorganizes. func TestLogRebirth(t *testing.T) { + testLogRebirth(t, rawdb.HashScheme) + testLogRebirth(t, rawdb.PathScheme) +} + +func testLogRebirth(t *testing.T, scheme string) { var ( key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") addr1 = crypto.PubkeyToAddress(key1.PublicKey) gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000000)}}} signer = types.LatestSigner(gspec.Config) engine = ethash.NewFaker() - blockchain, _ = NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil) + blockchain, _ = NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil) ) defer blockchain.Stop() @@ -1222,12 +1337,17 @@ func TestLogRebirth(t *testing.T) { // This test is a variation of TestLogRebirth. It verifies that log events are emitted // when a side chain containing log events overtakes the canonical chain. func TestSideLogRebirth(t *testing.T) { + testSideLogRebirth(t, rawdb.HashScheme) + testSideLogRebirth(t, rawdb.PathScheme) +} + +func testSideLogRebirth(t *testing.T, scheme string) { var ( key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") addr1 = crypto.PubkeyToAddress(key1.PublicKey) gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000000)}}} signer = types.LatestSigner(gspec.Config) - blockchain, _ = NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ = NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) ) defer blockchain.Stop() @@ -1312,6 +1432,11 @@ func checkLogEvents(t *testing.T, logsCh <-chan []*types.Log, rmLogsCh <-chan Re } func TestReorgSideEvent(t *testing.T) { + testReorgSideEvent(t, rawdb.HashScheme) + testReorgSideEvent(t, rawdb.PathScheme) +} + +func testReorgSideEvent(t *testing.T, scheme string) { var ( key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") addr1 = crypto.PubkeyToAddress(key1.PublicKey) @@ -1321,7 +1446,7 @@ func TestReorgSideEvent(t *testing.T) { } signer = types.LatestSigner(gspec.Config) ) - blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer blockchain.Stop() _, chain, _ := GenerateChainWithGenesis(gspec, ethash.NewFaker(), 3, func(i int, gen *BlockGen) {}) @@ -1392,7 +1517,12 @@ done: // Tests if the canonical block can be fetched from the database during chain insertion. func TestCanonicalBlockRetrieval(t *testing.T) { - _, gspec, blockchain, err := newCanonical(ethash.NewFaker(), 0, true) + testCanonicalBlockRetrieval(t, rawdb.HashScheme) + testCanonicalBlockRetrieval(t, rawdb.PathScheme) +} + +func testCanonicalBlockRetrieval(t *testing.T, scheme string) { + _, gspec, blockchain, err := newCanonical(ethash.NewFaker(), 0, true, scheme) if err != nil { t.Fatalf("failed to create pristine chain: %v", err) } @@ -1436,8 +1566,12 @@ func TestCanonicalBlockRetrieval(t *testing.T) { } pend.Wait() } - func TestEIP155Transition(t *testing.T) { + testEIP155Transition(t, rawdb.HashScheme) + testEIP155Transition(t, rawdb.PathScheme) +} + +func testEIP155Transition(t *testing.T, scheme string) { // Configure and generate a sample block chain var ( key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") @@ -1496,7 +1630,7 @@ func TestEIP155Transition(t *testing.T) { } }) - blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer blockchain.Stop() if _, err := blockchain.InsertChain(blocks); err != nil { @@ -1546,8 +1680,12 @@ func TestEIP155Transition(t *testing.T) { t.Errorf("have %v, want %v", have, want) } } - func TestEIP161AccountRemoval(t *testing.T) { + testEIP161AccountRemoval(t, rawdb.HashScheme) + testEIP161AccountRemoval(t, rawdb.PathScheme) +} + +func testEIP161AccountRemoval(t *testing.T, scheme string) { // Configure and generate a sample block chain var ( key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") @@ -1585,7 +1723,7 @@ func TestEIP161AccountRemoval(t *testing.T) { block.AddTx(tx) }) // account must exist pre eip 161 - blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer blockchain.Stop() if _, err := blockchain.InsertChain(types.Blocks{blocks[0]}); err != nil { @@ -1618,6 +1756,11 @@ func TestEIP161AccountRemoval(t *testing.T) { // // https://github.com/ethereum/go-ethereum/pull/15941 func TestBlockchainHeaderchainReorgConsistency(t *testing.T) { + testBlockchainHeaderchainReorgConsistency(t, rawdb.HashScheme) + testBlockchainHeaderchainReorgConsistency(t, rawdb.PathScheme) +} + +func testBlockchainHeaderchainReorgConsistency(t *testing.T, scheme string) { // Generate a canonical chain to act as the main dataset engine := ethash.NewFaker() genesis := &Genesis{ @@ -1638,7 +1781,7 @@ func TestBlockchainHeaderchainReorgConsistency(t *testing.T) { } // Import the canonical and fork chain side by side, verifying the current block // and current header consistency - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, genesis, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -1698,10 +1841,10 @@ func TestTrieForkGC(t *testing.T) { } // Dereference all the recent tries and ensure no past trie is left in for i := 0; i < TriesInMemory; i++ { - chain.stateCache.TrieDB().Dereference(blocks[len(blocks)-1-i].Root()) - chain.stateCache.TrieDB().Dereference(forks[len(blocks)-1-i].Root()) + chain.TrieDB().Dereference(blocks[len(blocks)-1-i].Root()) + chain.TrieDB().Dereference(forks[len(blocks)-1-i].Root()) } - if nodes, _ := chain.TrieDB().Size(); nodes > 0 { + if _, nodes, _ := chain.TrieDB().Size(); nodes > 0 { // all memory is returned in the nodes return for hashdb t.Fatalf("stale tries still alive after garbase collection") } } @@ -1709,6 +1852,11 @@ func TestTrieForkGC(t *testing.T) { // Tests that doing large reorgs works even if the state associated with the // forking point is not available any more. func TestLargeReorgTrieGC(t *testing.T) { + testLargeReorgTrieGC(t, rawdb.HashScheme) + testLargeReorgTrieGC(t, rawdb.PathScheme) +} + +func testLargeReorgTrieGC(t *testing.T, scheme string) { // Generate the original common chain segment and the two competing forks engine := ethash.NewFaker() genesis := &Genesis{ @@ -1720,7 +1868,10 @@ func TestLargeReorgTrieGC(t *testing.T) { competitor, _ := GenerateChain(genesis.Config, shared[len(shared)-1], engine, genDb, 2*TriesInMemory+1, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{3}) }) // Import the shared chain and the original canonical one - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, genesis, nil, engine, vm.Config{}, nil, nil) + db, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false) + defer db.Close() + + chain, err := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -1733,7 +1884,7 @@ func TestLargeReorgTrieGC(t *testing.T) { t.Fatalf("failed to insert original chain: %v", err) } // Ensure that the state associated with the forking point is pruned away - if node, _ := chain.stateCache.TrieDB().Node(shared[len(shared)-1].Root()); node != nil { + 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 @@ -1742,7 +1893,7 @@ func TestLargeReorgTrieGC(t *testing.T) { t.Fatalf("failed to insert competitor chain: %v", err) } for i, block := range competitor[:len(competitor)-2] { - if node, _ := chain.stateCache.TrieDB().Node(block.Root()); node != nil { + if chain.HasState(block.Root()) { t.Fatalf("competitor %d: low TD chain became processed", i) } } @@ -1751,14 +1902,30 @@ func TestLargeReorgTrieGC(t *testing.T) { if _, err := chain.InsertChain(competitor[len(competitor)-2:]); err != nil { t.Fatalf("failed to finalize competitor chain: %v", err) } - for i, block := range competitor[:len(competitor)-TriesInMemory] { - if node, _ := chain.stateCache.TrieDB().Node(block.Root()); node != nil { + // 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 + if scheme == rawdb.PathScheme { + states = states + 1 + } + for i, block := range competitor[:len(competitor)-states] { + if chain.HasState(block.Root()) { + t.Fatalf("competitor %d: unexpected competing chain state", i) + } + } + for i, block := range competitor[len(competitor)-states:] { + if !chain.HasState(block.Root()) { t.Fatalf("competitor %d: competing chain state missing", i) } } } func TestBlockchainRecovery(t *testing.T) { + testBlockchainRecovery(t, rawdb.HashScheme) + testBlockchainRecovery(t, rawdb.PathScheme) +} + +func testBlockchainRecovery(t *testing.T, scheme string) { // Configure and generate a sample block chain var ( key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") @@ -1775,7 +1942,7 @@ func TestBlockchainRecovery(t *testing.T) { t.Fatalf("failed to create temp freezer db: %v", err) } defer ancientDb.Close() - ancient, _ := NewBlockChain(ancientDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + ancient, _ := NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) headers := make([]*types.Header, len(blocks)) for i, block := range blocks { @@ -1795,7 +1962,7 @@ func TestBlockchainRecovery(t *testing.T) { rawdb.WriteHeadFastBlockHash(ancientDb, midBlock.Hash()) // Reopen broken blockchain again - ancient, _ = NewBlockChain(ancientDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + ancient, _ = NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer ancient.Stop() if num := ancient.CurrentBlock().Number.Uint64(); num != 0 { t.Errorf("head block mismatch: have #%v, want #%v", num, 0) @@ -1810,8 +1977,13 @@ func TestBlockchainRecovery(t *testing.T) { // This test checks that InsertReceiptChain will roll back correctly when attempting to insert a side chain. func TestInsertReceiptChainRollback(t *testing.T) { + testInsertReceiptChainRollback(t, rawdb.HashScheme) + testInsertReceiptChainRollback(t, rawdb.PathScheme) +} + +func testInsertReceiptChainRollback(t *testing.T, scheme string) { // Generate forked chain. The returned BlockChain object is used to process the side chain blocks. - tmpChain, sideblocks, canonblocks, gspec, err := getLongAndShortChains() + tmpChain, sideblocks, canonblocks, gspec, err := getLongAndShortChains(scheme) if err != nil { t.Fatal(err) } @@ -1842,7 +2014,7 @@ func TestInsertReceiptChainRollback(t *testing.T) { } defer ancientDb.Close() - ancientChain, _ := NewBlockChain(ancientDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + ancientChain, _ := NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer ancientChain.Stop() // Import the canonical header chain. @@ -1887,6 +2059,11 @@ func TestInsertReceiptChainRollback(t *testing.T) { // - https://github.com/ethereum/go-ethereum/issues/18977 // - https://github.com/ethereum/go-ethereum/pull/18988 func TestLowDiffLongChain(t *testing.T) { + testLowDiffLongChain(t, rawdb.HashScheme) + testLowDiffLongChain(t, rawdb.PathScheme) +} + +func testLowDiffLongChain(t *testing.T, scheme string) { // Generate a canonical chain to act as the main dataset engine := ethash.NewFaker() genesis := &Genesis{ @@ -1901,11 +2078,14 @@ func TestLowDiffLongChain(t *testing.T) { }) // Import the canonical chain - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, genesis, nil, engine, vm.Config{}, nil, nil) + diskdb, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false) + defer diskdb.Close() + + chain, err := NewBlockChain(diskdb, DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } - defer chain.stopWithoutSaving() + defer chain.Stop() if n, err := chain.InsertChain(blocks); err != nil { t.Fatalf("block %d: failed to insert into chain: %v", n, err) @@ -2085,11 +2265,20 @@ func TestPrunedImportSideWithMerging(t *testing.T) { testSideImport(t, 1, -10, 1) } -func TestInsertKnownHeaders(t *testing.T) { testInsertKnownChainData(t, "headers") } -func TestInsertKnownReceiptChain(t *testing.T) { testInsertKnownChainData(t, "receipts") } -func TestInsertKnownBlocks(t *testing.T) { testInsertKnownChainData(t, "blocks") } +func TestInsertKnownHeaders(t *testing.T) { + testInsertKnownChainData(t, "headers", rawdb.HashScheme) + testInsertKnownChainData(t, "headers", rawdb.PathScheme) +} +func TestInsertKnownReceiptChain(t *testing.T) { + testInsertKnownChainData(t, "receipts", rawdb.HashScheme) + testInsertKnownChainData(t, "receipts", rawdb.PathScheme) +} +func TestInsertKnownBlocks(t *testing.T) { + testInsertKnownChainData(t, "blocks", rawdb.HashScheme) + testInsertKnownChainData(t, "blocks", rawdb.PathScheme) +} -func testInsertKnownChainData(t *testing.T, typ string) { +func testInsertKnownChainData(t *testing.T, typ string, scheme string) { engine := ethash.NewFaker() genesis := &Genesis{ Config: params.TestChainConfig, @@ -2112,7 +2301,7 @@ func testInsertKnownChainData(t *testing.T, typ string) { } defer chaindb.Close() - chain, err := NewBlockChain(chaindb, nil, genesis, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(chaindb, DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -2385,7 +2574,7 @@ func testInsertKnownChainDataWithMerging(t *testing.T, typ string, mergeHeight i } // getLongAndShortChains returns two chains: A is longer, B is heavier. -func getLongAndShortChains() (*BlockChain, []*types.Block, []*types.Block, *Genesis, error) { +func getLongAndShortChains(scheme string) (*BlockChain, []*types.Block, []*types.Block, *Genesis, error) { // Generate a canonical chain to act as the main dataset engine := ethash.NewFaker() genesis := &Genesis{ @@ -2397,7 +2586,7 @@ func getLongAndShortChains() (*BlockChain, []*types.Block, []*types.Block, *Gene genDb, longChain, _ := GenerateChainWithGenesis(genesis, engine, 80, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, genesis, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil) if err != nil { return nil, nil, nil, nil, fmt.Errorf("failed to create tester chain: %v", err) } @@ -2443,7 +2632,12 @@ func getLongAndShortChains() (*BlockChain, []*types.Block, []*types.Block, *Gene // 3. Then there should be no canon mapping for the block at height X // 4. The forked block should still be retrievable by hash func TestReorgToShorterRemovesCanonMapping(t *testing.T) { - chain, canonblocks, sideblocks, _, err := getLongAndShortChains() + testReorgToShorterRemovesCanonMapping(t, rawdb.HashScheme) + testReorgToShorterRemovesCanonMapping(t, rawdb.PathScheme) +} + +func testReorgToShorterRemovesCanonMapping(t *testing.T, scheme string) { + chain, canonblocks, sideblocks, _, err := getLongAndShortChains(scheme) if err != nil { t.Fatal(err) } @@ -2481,7 +2675,12 @@ func TestReorgToShorterRemovesCanonMapping(t *testing.T) { // as TestReorgToShorterRemovesCanonMapping, but applied on headerchain // imports -- that is, for fast sync func TestReorgToShorterRemovesCanonMappingHeaderChain(t *testing.T) { - chain, canonblocks, sideblocks, _, err := getLongAndShortChains() + testReorgToShorterRemovesCanonMappingHeaderChain(t, rawdb.HashScheme) + testReorgToShorterRemovesCanonMappingHeaderChain(t, rawdb.PathScheme) +} + +func testReorgToShorterRemovesCanonMappingHeaderChain(t *testing.T, scheme string) { + chain, canonblocks, sideblocks, _, err := getLongAndShortChains(scheme) if err != nil { t.Fatal(err) } @@ -2624,6 +2823,11 @@ func TestTransactionIndices(t *testing.T) { } func TestSkipStaleTxIndicesInSnapSync(t *testing.T) { + testSkipStaleTxIndicesInSnapSync(t, rawdb.HashScheme) + testSkipStaleTxIndicesInSnapSync(t, rawdb.PathScheme) +} + +func testSkipStaleTxIndicesInSnapSync(t *testing.T, scheme string) { // Configure and generate a sample block chain var ( key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") @@ -2682,7 +2886,7 @@ func TestSkipStaleTxIndicesInSnapSync(t *testing.T) { // Import all blocks into ancient db, only HEAD-32 indices are kept. l := uint64(32) - chain, err := NewBlockChain(ancientDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, &l) + chain, err := NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, &l) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -2816,6 +3020,11 @@ func BenchmarkBlockChain_1x1000Executions(b *testing.B) { // 2. Downloader starts to sync again // 3. The blocks fetched are all known and canonical blocks func TestSideImportPrunedBlocks(t *testing.T) { + testSideImportPrunedBlocks(t, rawdb.HashScheme) + testSideImportPrunedBlocks(t, rawdb.PathScheme) +} + +func testSideImportPrunedBlocks(t *testing.T, scheme string) { // Generate a canonical chain to act as the main dataset engine := ethash.NewFaker() genesis := &Genesis{ @@ -2825,7 +3034,7 @@ func TestSideImportPrunedBlocks(t *testing.T) { // Generate and import the canonical chain _, blocks, _ := GenerateChainWithGenesis(genesis, engine, 2*TriesInMemory, nil) - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, genesis, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -2834,15 +3043,20 @@ func TestSideImportPrunedBlocks(t *testing.T) { if n, err := chain.InsertChain(blocks); err != nil { t.Fatalf("block %d: failed to insert into chain: %v", n, err) } - - lastPrunedIndex := len(blocks) - TriesInMemory - 1 + // 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 + if scheme == rawdb.PathScheme { + states = TriesInMemory + 1 + } + lastPrunedIndex := len(blocks) - states - 1 lastPrunedBlock := blocks[lastPrunedIndex] // Verify pruning of lastPrunedBlock if chain.HasBlockAndState(lastPrunedBlock.Hash(), lastPrunedBlock.NumberU64()) { t.Errorf("Block %d not pruned", lastPrunedBlock.NumberU64()) } - firstNonPrunedBlock := blocks[len(blocks)-TriesInMemory] + firstNonPrunedBlock := blocks[len(blocks)-states] // Verify firstNonPrunedBlock is not pruned if !chain.HasBlockAndState(firstNonPrunedBlock.Hash(), firstNonPrunedBlock.NumberU64()) { t.Errorf("Block %d pruned", firstNonPrunedBlock.NumberU64()) @@ -2864,6 +3078,11 @@ func TestSideImportPrunedBlocks(t *testing.T) { // each transaction, so this works ok. The rework accumulated writes in memory // first, but the journal wiped the entire state object on create-revert. func TestDeleteCreateRevert(t *testing.T) { + testDeleteCreateRevert(t, rawdb.HashScheme) + testDeleteCreateRevert(t, rawdb.PathScheme) +} + +func testDeleteCreateRevert(t *testing.T, scheme string) { var ( aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa") bb = common.HexToAddress("0x000000000000000000000000000000000000bbbb") @@ -2915,7 +3134,7 @@ func TestDeleteCreateRevert(t *testing.T) { b.AddTx(tx) }) // Import the canonical chain - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -2934,6 +3153,11 @@ func TestDeleteCreateRevert(t *testing.T) { // Expected outcome is that _all_ slots are cleared from A, due to the selfdestruct, // and then the new slots exist func TestDeleteRecreateSlots(t *testing.T) { + testDeleteRecreateSlots(t, rawdb.HashScheme) + testDeleteRecreateSlots(t, rawdb.PathScheme) +} + +func testDeleteRecreateSlots(t *testing.T, scheme string) { var ( engine = ethash.NewFaker() @@ -3023,7 +3247,7 @@ func TestDeleteRecreateSlots(t *testing.T) { b.AddTx(tx) }) // Import the canonical chain - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{ + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{ Tracer: logger.NewJSONLogger(nil, os.Stdout), }, nil, nil) if err != nil { @@ -3057,6 +3281,11 @@ func TestDeleteRecreateSlots(t *testing.T) { // regular value-transfer // Expected outcome is that _all_ slots are cleared from A func TestDeleteRecreateAccount(t *testing.T) { + testDeleteRecreateAccount(t, rawdb.HashScheme) + testDeleteRecreateAccount(t, rawdb.PathScheme) +} + +func testDeleteRecreateAccount(t *testing.T, scheme string) { var ( engine = ethash.NewFaker() @@ -3100,7 +3329,7 @@ func TestDeleteRecreateAccount(t *testing.T) { b.AddTx(tx) }) // Import the canonical chain - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{ + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{ Tracer: logger.NewJSONLogger(nil, os.Stdout), }, nil, nil) if err != nil { @@ -3130,6 +3359,11 @@ func TestDeleteRecreateAccount(t *testing.T) { // Expected outcome is that _all_ slots are cleared from A, due to the selfdestruct, // and then the new slots exist func TestDeleteRecreateSlotsAcrossManyBlocks(t *testing.T) { + testDeleteRecreateSlotsAcrossManyBlocks(t, rawdb.HashScheme) + testDeleteRecreateSlotsAcrossManyBlocks(t, rawdb.PathScheme) +} + +func testDeleteRecreateSlotsAcrossManyBlocks(t *testing.T, scheme string) { var ( engine = ethash.NewFaker() @@ -3270,7 +3504,7 @@ func TestDeleteRecreateSlotsAcrossManyBlocks(t *testing.T) { current = exp }) // Import the canonical chain - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{ + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{ //Debug: true, //Tracer: vm.NewJSONLogger(nil, os.Stdout), }, nil, nil) @@ -3328,7 +3562,14 @@ func TestDeleteRecreateSlotsAcrossManyBlocks(t *testing.T) { // to the destructset in case something is created "onto" an existing item. // We need to either roll back the snapDestructs, or not place it into snapDestructs // in the first place. +// + func TestInitThenFailCreateContract(t *testing.T) { + testInitThenFailCreateContract(t, rawdb.HashScheme) + testInitThenFailCreateContract(t, rawdb.PathScheme) +} + +func testInitThenFailCreateContract(t *testing.T, scheme string) { var ( engine = ethash.NewFaker() @@ -3401,7 +3642,7 @@ func TestInitThenFailCreateContract(t *testing.T) { }) // Import the canonical chain - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{ + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{ //Debug: true, //Tracer: vm.NewJSONLogger(nil, os.Stdout), }, nil, nil) @@ -3439,6 +3680,11 @@ func TestInitThenFailCreateContract(t *testing.T) { // checking that the gas usage of a hot SLOAD and a cold SLOAD are calculated // correctly. func TestEIP2718Transition(t *testing.T) { + testEIP2718Transition(t, rawdb.HashScheme) + testEIP2718Transition(t, rawdb.PathScheme) +} + +func testEIP2718Transition(t *testing.T, scheme string) { var ( aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa") engine = ethash.NewFaker() @@ -3486,7 +3732,7 @@ func TestEIP2718Transition(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(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -3516,6 +3762,11 @@ func TestEIP2718Transition(t *testing.T) { // gasFeeCap - gasTipCap < baseFee. // 6. Legacy transaction behave as expected (e.g. gasPrice = gasFeeCap = gasTipCap). func TestEIP1559Transition(t *testing.T) { + testEIP1559Transition(t, rawdb.HashScheme) + testEIP1559Transition(t, rawdb.PathScheme) +} + +func testEIP1559Transition(t *testing.T, scheme string) { var ( aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa") engine = ethash.NewFaker() @@ -3526,8 +3777,9 @@ func TestEIP1559Transition(t *testing.T) { addr1 = crypto.PubkeyToAddress(key1.PublicKey) addr2 = crypto.PubkeyToAddress(key2.PublicKey) funds = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether)) + config = *params.AllEthashProtocolChanges gspec = &Genesis{ - Config: params.AllEthashProtocolChanges, + Config: &config, Alloc: GenesisAlloc{ addr1: {Balance: funds}, addr2: {Balance: funds}, @@ -3574,7 +3826,7 @@ func TestEIP1559Transition(t *testing.T) { b.AddTx(tx) }) - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -3656,6 +3908,11 @@ func TestEIP1559Transition(t *testing.T) { // Tests the scenario the chain is requested to another point with the missing state. // It expects the state is recovered and all relevant chain markers are set correctly. func TestSetCanonical(t *testing.T) { + testSetCanonical(t, rawdb.HashScheme) + testSetCanonical(t, rawdb.PathScheme) +} + +func testSetCanonical(t *testing.T, scheme string) { //log.Root().SetHandler(log.LvlFilterHandler(log.LvlDebug, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) var ( @@ -3678,7 +3935,10 @@ func TestSetCanonical(t *testing.T) { } gen.AddTx(tx) }) - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil) + diskdb, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false) + defer diskdb.Close() + + chain, err := NewBlockChain(diskdb, DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -3735,6 +3995,11 @@ func TestSetCanonical(t *testing.T) { // TestCanonicalHashMarker tests all the canonical hash markers are updated/deleted // correctly in case reorg is called. func TestCanonicalHashMarker(t *testing.T) { + testCanonicalHashMarker(t, rawdb.HashScheme) + testCanonicalHashMarker(t, rawdb.PathScheme) +} + +func testCanonicalHashMarker(t *testing.T, scheme string) { var cases = []struct { forkA int forkB int @@ -3782,7 +4047,7 @@ func TestCanonicalHashMarker(t *testing.T) { _, forkB, _ := GenerateChainWithGenesis(gspec, engine, c.forkB, func(i int, gen *BlockGen) {}) // Initialize test chain - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -4129,6 +4394,7 @@ func testCreateThenDelete(t *testing.T, config *params.ChainConfig) { if err != nil { t.Fatalf("failed to create tester chain: %v", err) } + defer chain.Stop() // Import the blocks for _, block := range blocks { if _, err := chain.InsertChain([]*types.Block{block}); err != nil { @@ -4137,6 +4403,116 @@ func testCreateThenDelete(t *testing.T, config *params.ChainConfig) { } } +func TestDeleteThenCreate(t *testing.T) { + var ( + engine = ethash.NewFaker() + key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + address = crypto.PubkeyToAddress(key.PublicKey) + factoryAddr = crypto.CreateAddress(address, 0) + funds = big.NewInt(1000000000000000) + ) + /* + contract Factory { + function deploy(bytes memory code) public { + address addr; + assembly { + addr := create2(0, add(code, 0x20), mload(code), 0) + if iszero(extcodesize(addr)) { + revert(0, 0) + } + } + } + } + */ + factoryBIN := common.Hex2Bytes("608060405234801561001057600080fd5b50610241806100206000396000f3fe608060405234801561001057600080fd5b506004361061002a5760003560e01c80627743601461002f575b600080fd5b610049600480360381019061004491906100d8565b61004b565b005b6000808251602084016000f59050803b61006457600080fd5b5050565b600061007b61007684610146565b610121565b905082815260208101848484011115610097576100966101eb565b5b6100a2848285610177565b509392505050565b600082601f8301126100bf576100be6101e6565b5b81356100cf848260208601610068565b91505092915050565b6000602082840312156100ee576100ed6101f5565b5b600082013567ffffffffffffffff81111561010c5761010b6101f0565b5b610118848285016100aa565b91505092915050565b600061012b61013c565b90506101378282610186565b919050565b6000604051905090565b600067ffffffffffffffff821115610161576101606101b7565b5b61016a826101fa565b9050602081019050919050565b82818337600083830152505050565b61018f826101fa565b810181811067ffffffffffffffff821117156101ae576101ad6101b7565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f830116905091905056fea2646970667358221220ea8b35ed310d03b6b3deef166941140b4d9e90ea2c92f6b41eb441daf49a59c364736f6c63430008070033") + + /* + contract C { + uint256 value; + constructor() { + value = 100; + } + function destruct() public payable { + selfdestruct(payable(msg.sender)); + } + receive() payable external {} + } + */ + contractABI := common.Hex2Bytes("6080604052348015600f57600080fd5b5060646000819055506081806100266000396000f3fe608060405260043610601f5760003560e01c80632b68b9c614602a576025565b36602557005b600080fd5b60306032565b005b3373ffffffffffffffffffffffffffffffffffffffff16fffea2646970667358221220ab749f5ed1fcb87bda03a74d476af3f074bba24d57cb5a355e8162062ad9a4e664736f6c63430008070033") + contractAddr := crypto.CreateAddress2(factoryAddr, [32]byte{}, crypto.Keccak256(contractABI)) + + gspec := &Genesis{ + Config: params.TestChainConfig, + Alloc: GenesisAlloc{ + address: {Balance: funds}, + }, + } + nonce := uint64(0) + signer := types.HomesteadSigner{} + _, blocks, _ := GenerateChainWithGenesis(gspec, engine, 2, func(i int, b *BlockGen) { + fee := big.NewInt(1) + if b.header.BaseFee != nil { + fee = b.header.BaseFee + } + b.SetCoinbase(common.Address{1}) + + // Block 1 + if i == 0 { + tx, _ := types.SignNewTx(key, signer, &types.LegacyTx{ + Nonce: nonce, + GasPrice: new(big.Int).Set(fee), + Gas: 500000, + Data: factoryBIN, + }) + nonce++ + b.AddTx(tx) + + data := common.Hex2Bytes("00774360000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a76080604052348015600f57600080fd5b5060646000819055506081806100266000396000f3fe608060405260043610601f5760003560e01c80632b68b9c614602a576025565b36602557005b600080fd5b60306032565b005b3373ffffffffffffffffffffffffffffffffffffffff16fffea2646970667358221220ab749f5ed1fcb87bda03a74d476af3f074bba24d57cb5a355e8162062ad9a4e664736f6c6343000807003300000000000000000000000000000000000000000000000000") + tx, _ = types.SignNewTx(key, signer, &types.LegacyTx{ + Nonce: nonce, + GasPrice: new(big.Int).Set(fee), + Gas: 500000, + To: &factoryAddr, + Data: data, + }) + b.AddTx(tx) + nonce++ + } else { + // Block 2 + tx, _ := types.SignNewTx(key, signer, &types.LegacyTx{ + Nonce: nonce, + GasPrice: new(big.Int).Set(fee), + Gas: 500000, + To: &contractAddr, + Data: common.Hex2Bytes("2b68b9c6"), // destruct + }) + nonce++ + b.AddTx(tx) + + data := common.Hex2Bytes("00774360000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a76080604052348015600f57600080fd5b5060646000819055506081806100266000396000f3fe608060405260043610601f5760003560e01c80632b68b9c614602a576025565b36602557005b600080fd5b60306032565b005b3373ffffffffffffffffffffffffffffffffffffffff16fffea2646970667358221220ab749f5ed1fcb87bda03a74d476af3f074bba24d57cb5a355e8162062ad9a4e664736f6c6343000807003300000000000000000000000000000000000000000000000000") + tx, _ = types.SignNewTx(key, signer, &types.LegacyTx{ + Nonce: nonce, + GasPrice: new(big.Int).Set(fee), + Gas: 500000, + To: &factoryAddr, // re-creation + Data: data, + }) + b.AddTx(tx) + nonce++ + } + }) + // Import the canonical chain + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil) + if err != nil { + t.Fatalf("failed to create tester chain: %v", err) + } + for _, block := range blocks { + if _, err := chain.InsertChain([]*types.Block{block}); err != nil { + t.Fatalf("block %d: failed to insert into chain: %v", block.NumberU64(), err) + } + } +} + // TestTransientStorageReset ensures the transient storage is wiped correctly // between transactions. func TestTransientStorageReset(t *testing.T) { @@ -4215,6 +4591,7 @@ func TestTransientStorageReset(t *testing.T) { if err != nil { t.Fatalf("failed to create tester chain: %v", err) } + defer chain.Stop() // Import the blocks if _, err := chain.InsertChain(blocks); err != nil { t.Fatalf("failed to insert into chain: %v", err) @@ -4309,6 +4686,7 @@ func TestEIP3651(t *testing.T) { 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) } diff --git a/core/chain_indexer.go b/core/chain_indexer.go index 23ab23ef0f..f5fce72588 100644 --- a/core/chain_indexer.go +++ b/core/chain_indexer.go @@ -19,6 +19,7 @@ package core import ( "context" "encoding/binary" + "errors" "fmt" "sync" "sync/atomic" @@ -403,7 +404,7 @@ func (c *ChainIndexer) processSection(section uint64, lastHead common.Hash) (com if header == nil { return common.Hash{}, fmt.Errorf("block #%d [%x..] not found", number, hash[:4]) } else if header.ParentHash != lastHead { - return common.Hash{}, fmt.Errorf("chain reorged during section processing") + return common.Hash{}, errors.New("chain reorged during section processing") } if err := c.backend.Process(c.ctx, header); err != nil { return common.Hash{}, err diff --git a/core/chain_makers.go b/core/chain_makers.go index 61d0098af3..c9c880dd69 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -23,6 +23,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/misc" + "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" @@ -86,6 +88,11 @@ func (b *BlockGen) SetPoS() { b.header.Difficulty = new(big.Int) } +// SetBlobGas sets the data gas used by the blob in the generated block. +func (b *BlockGen) SetBlobGas(blobGasUsed uint64) { + b.header.BlobGasUsed = &blobGasUsed +} + // addTx adds a transaction to the generated block. If no coinbase has // been set, the block's coinbase is set to the zero address. // @@ -202,7 +209,7 @@ func (b *BlockGen) AddUncle(h *types.Header) { // The gas limit and price should be derived from the parent h.GasLimit = parent.GasLimit if b.config.IsLondon(h.Number) { - h.BaseFee = misc.CalcBaseFee(b.config, parent) + h.BaseFee = eip1559.CalcBaseFee(b.config, parent) if !b.config.IsLondon(parent.Number) { parentGasLimit := parent.GasLimit * b.config.ElasticityMultiplier() h.GasLimit = CalcGasLimit(parentGasLimit, parentGasLimit) @@ -282,7 +289,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse } blocks, receipts := make(types.Blocks, n), make([]types.Receipts, n) chainreader := &fakeChainReader{config: config} - genblock := func(i int, parent *types.Block, statedb *state.StateDB) (*types.Block, types.Receipts) { + genblock := func(i int, parent *types.Block, triedb *trie.Database, statedb *state.StateDB) (*types.Block, types.Receipts) { b := &BlockGen{i: i, chain: blocks, parent: parent, statedb: statedb, config: config, engine: engine} b.header = makeHeader(chainreader, parent, statedb, b.engine) @@ -321,23 +328,27 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse } // Write state changes to db - root, err := statedb.Commit(config.IsEIP158(b.header.Number)) + 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 := statedb.Database().TrieDB().Commit(root, false); err != nil { + if err = triedb.Commit(root, false); err != nil { panic(fmt.Sprintf("trie write error: %v", err)) } return block, b.receipts } return nil, nil } + // Forcibly use hash-based state scheme for retaining all nodes in disk. + triedb := trie.NewDatabase(db, trie.HashDefaults) + defer triedb.Close() + for i := 0; i < n; i++ { - statedb, err := state.New(parent.Root(), state.NewDatabase(db), nil) + statedb, err := state.New(parent.Root(), state.NewDatabaseWithNodeDB(db, triedb), nil) if err != nil { panic(err) } - block, receipt := genblock(i, parent, statedb) + block, receipt := genblock(i, parent, triedb, statedb) blocks[i] = block receipts[i] = receipt parent = block @@ -350,7 +361,9 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse // then generate chain on top. func GenerateChainWithGenesis(genesis *Genesis, engine consensus.Engine, n int, gen func(int, *BlockGen)) (ethdb.Database, []*types.Block, []types.Receipts) { db := rawdb.NewMemoryDatabase() - _, err := genesis.Commit(db, trie.NewDatabase(db)) + triedb := trie.NewDatabase(db, trie.HashDefaults) + defer triedb.Close() + _, err := genesis.Commit(db, triedb) if err != nil { panic(err) } @@ -380,12 +393,26 @@ func makeHeader(chain consensus.ChainReader, parent *types.Block, state *state.S Time: time, } if chain.Config().IsLondon(header.Number) { - header.BaseFee = misc.CalcBaseFee(chain.Config(), parent.Header()) + header.BaseFee = eip1559.CalcBaseFee(chain.Config(), parent.Header()) if !chain.Config().IsLondon(parent.Number()) { parentGasLimit := parent.GasLimit() * chain.Config().ElasticityMultiplier() header.GasLimit = CalcGasLimit(parentGasLimit, parentGasLimit) } } + if chain.Config().IsCancun(header.Number, header.Time) { + var ( + parentExcessBlobGas uint64 + parentBlobGasUsed uint64 + ) + if parent.ExcessBlobGas() != nil { + parentExcessBlobGas = *parent.ExcessBlobGas() + parentBlobGasUsed = *parent.BlobGasUsed() + } + excessBlobGas := eip4844.CalcExcessBlobGas(parentExcessBlobGas, parentBlobGasUsed) + header.ExcessBlobGas = &excessBlobGas + header.BlobGasUsed = new(uint64) + header.ParentBeaconRoot = new(common.Hash) + } return header } diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go index 4f73555275..db220cf24a 100644 --- a/core/chain_makers_test.go +++ b/core/chain_makers_test.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/trie" ) func TestGenerateWithdrawalChain(t *testing.T) { @@ -74,8 +75,7 @@ func TestGenerateWithdrawalChain(t *testing.T) { Storage: storage, Code: common.Hex2Bytes("600154600354"), } - - genesis := gspec.MustCommit(gendb) + genesis := gspec.MustCommit(gendb, trie.NewDatabase(gendb, trie.HashDefaults)) chain, _ := GenerateChain(gspec.Config, genesis, beacon.NewFaker(), gendb, 4, func(i int, gen *BlockGen) { tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(address), address, big.NewInt(1000), params.TxGas, new(big.Int).Add(gen.BaseFee(), common.Big1), nil), signer, key) @@ -146,6 +146,7 @@ func ExampleGenerateChain() { addr2 = crypto.PubkeyToAddress(key2.PublicKey) addr3 = crypto.PubkeyToAddress(key3.PublicKey) db = rawdb.NewMemoryDatabase() + genDb = rawdb.NewMemoryDatabase() ) // Ensure that key1 has some funds in the genesis block. @@ -153,13 +154,13 @@ func ExampleGenerateChain() { Config: ¶ms.ChainConfig{HomesteadBlock: new(big.Int)}, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(1000000)}}, } - genesis := gspec.MustCommit(db) + genesis := gspec.MustCommit(genDb, trie.NewDatabase(genDb, trie.HashDefaults)) // This call generates a chain of 5 blocks. The function runs for // each block and adds different features to gen based on the // block index. signer := types.HomesteadSigner{} - chain, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 5, func(i int, gen *BlockGen) { + chain, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), genDb, 5, func(i int, gen *BlockGen) { switch i { case 0: // In block 1, addr1 sends addr2 some ether. @@ -188,7 +189,7 @@ func ExampleGenerateChain() { }) // Import the chain. This runs all block validation rules. - blockchain, _ := NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(db, DefaultCacheConfigWithScheme(rawdb.HashScheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, 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 f2e8dfe8f9..b9a899ef2f 100644 --- a/core/dao_test.go +++ b/core/dao_test.go @@ -83,7 +83,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { if _, err := bc.InsertChain(blocks); err != nil { t.Fatalf("failed to import contra-fork chain for expansion: %v", err) } - if err := bc.stateCache.TrieDB().Commit(bc.CurrentHeader().Root, false); err != nil { + if err := bc.triedb.Commit(bc.CurrentHeader().Root, false); err != nil { t.Fatalf("failed to commit contra-fork head for expansion: %v", err) } bc.Stop() @@ -106,7 +106,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { if _, err := bc.InsertChain(blocks); err != nil { t.Fatalf("failed to import pro-fork chain for expansion: %v", err) } - if err := bc.stateCache.TrieDB().Commit(bc.CurrentHeader().Root, false); err != nil { + if err := bc.triedb.Commit(bc.CurrentHeader().Root, false); err != nil { t.Fatalf("failed to commit pro-fork head for expansion: %v", err) } bc.Stop() @@ -131,7 +131,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { if _, err := bc.InsertChain(blocks); err != nil { t.Fatalf("failed to import contra-fork chain for expansion: %v", err) } - if err := bc.stateCache.TrieDB().Commit(bc.CurrentHeader().Root, false); err != nil { + if err := bc.triedb.Commit(bc.CurrentHeader().Root, false); err != nil { t.Fatalf("failed to commit contra-fork head for expansion: %v", err) } blocks, _ = GenerateChain(&proConf, conBc.GetBlockByHash(conBc.CurrentBlock().Hash()), ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {}) @@ -149,7 +149,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { if _, err := bc.InsertChain(blocks); err != nil { t.Fatalf("failed to import pro-fork chain for expansion: %v", err) } - if err := bc.stateCache.TrieDB().Commit(bc.CurrentHeader().Root, false); err != nil { + if err := bc.triedb.Commit(bc.CurrentHeader().Root, false); err != nil { t.Fatalf("failed to commit pro-fork head for expansion: %v", err) } blocks, _ = GenerateChain(&conConf, proBc.GetBlockByHash(proBc.CurrentBlock().Hash()), ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {}) diff --git a/core/error.go b/core/error.go index 872ba8d365..4214ed207a 100644 --- a/core/error.go +++ b/core/error.go @@ -100,4 +100,8 @@ var ( // ErrSenderNoEOA is returned if the sender of a transaction is a contract. ErrSenderNoEOA = errors.New("sender not an eoa") + + // ErrBlobFeeCapTooLow is returned if the transaction fee cap is less than the + // blob gas fee of the block. + ErrBlobFeeCapTooLow = errors.New("max fee per blob gas less than block blob gas fee") ) diff --git a/core/evm.go b/core/evm.go index bd4f2b0e55..104f2c09dc 100644 --- a/core/evm.go +++ b/core/evm.go @@ -56,24 +56,26 @@ func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common random = &header.MixDigest } return vm.BlockContext{ - CanTransfer: CanTransfer, - Transfer: Transfer, - GetHash: GetHashFn(header, chain), - Coinbase: beneficiary, - BlockNumber: new(big.Int).Set(header.Number), - Time: header.Time, - Difficulty: new(big.Int).Set(header.Difficulty), - BaseFee: baseFee, - GasLimit: header.GasLimit, - Random: random, + CanTransfer: CanTransfer, + Transfer: Transfer, + GetHash: GetHashFn(header, chain), + Coinbase: beneficiary, + BlockNumber: new(big.Int).Set(header.Number), + Time: header.Time, + Difficulty: new(big.Int).Set(header.Difficulty), + BaseFee: baseFee, + GasLimit: header.GasLimit, + Random: random, + ExcessBlobGas: header.ExcessBlobGas, } } // NewEVMTxContext creates a new transaction context for a single transaction. func NewEVMTxContext(msg *Message) vm.TxContext { return vm.TxContext{ - Origin: msg.From, - GasPrice: new(big.Int).Set(msg.GasPrice), + Origin: msg.From, + GasPrice: new(big.Int).Set(msg.GasPrice), + BlobHashes: msg.BlobHashes, } } diff --git a/core/forkid/forkid.go b/core/forkid/forkid.go index f536019dac..76825d3bef 100644 --- a/core/forkid/forkid.go +++ b/core/forkid/forkid.go @@ -24,13 +24,12 @@ import ( "math" "math/big" "reflect" - "sort" "strings" - "github.com/ethereum/go-ethereum/common" "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 ( @@ -73,12 +72,12 @@ type ID struct { type Filter func(id ID) error // NewID calculates the Ethereum fork ID from the chain config, genesis hash, head and time. -func NewID(config *params.ChainConfig, genesis common.Hash, head, time uint64) ID { +func NewID(config *params.ChainConfig, genesis *types.Block, head, time uint64) ID { // Calculate the starting checksum from the genesis hash - hash := crc32.ChecksumIEEE(genesis[:]) + hash := crc32.ChecksumIEEE(genesis.Hash().Bytes()) // Calculate the current fork checksum and the next fork block - forksByBlock, forksByTime := gatherForks(config) + forksByBlock, forksByTime := gatherForks(config, genesis.Time()) for _, fork := range forksByBlock { if fork <= head { // Fork already passed, checksum the previous hash and the fork number @@ -104,7 +103,7 @@ func NewIDWithChain(chain Blockchain) ID { return NewID( chain.Config(), - chain.Genesis().Hash(), + chain.Genesis(), head.Number.Uint64(), head.Time, ) @@ -115,7 +114,7 @@ func NewIDWithChain(chain Blockchain) ID { func NewFilter(chain Blockchain) Filter { return newFilter( chain.Config(), - chain.Genesis().Hash(), + chain.Genesis(), func() (uint64, uint64) { head := chain.CurrentHeader() return head.Number.Uint64(), head.Time @@ -124,7 +123,7 @@ func NewFilter(chain Blockchain) Filter { } // NewStaticFilter creates a filter at block zero. -func NewStaticFilter(config *params.ChainConfig, genesis common.Hash) Filter { +func NewStaticFilter(config *params.ChainConfig, genesis *types.Block) Filter { head := func() (uint64, uint64) { return 0, 0 } return newFilter(config, genesis, head) } @@ -132,14 +131,14 @@ func NewStaticFilter(config *params.ChainConfig, genesis common.Hash) Filter { // newFilter is the internal version of NewFilter, taking closures as its arguments // instead of a chain. The reason is to allow testing it without having to simulate // an entire blockchain. -func newFilter(config *params.ChainConfig, genesis common.Hash, headfn func() (uint64, uint64)) Filter { +func newFilter(config *params.ChainConfig, genesis *types.Block, headfn func() (uint64, uint64)) Filter { // Calculate the all the valid fork hash and fork next combos var ( - forksByBlock, forksByTime = gatherForks(config) + forksByBlock, forksByTime = gatherForks(config, genesis.Time()) forks = append(append([]uint64{}, forksByBlock...), forksByTime...) sums = make([][4]byte, len(forks)+1) // 0th is the genesis ) - hash := crc32.ChecksumIEEE(genesis[:]) + hash := crc32.ChecksumIEEE(genesis.Hash().Bytes()) sums[0] = checksumToBytes(hash) for i, fork := range forks { hash = checksumUpdate(hash, fork) @@ -240,7 +239,7 @@ func checksumToBytes(hash uint32) [4]byte { // gatherForks gathers all the known forks and creates two sorted lists out of // them, one for the block number based forks and the second for the timestamps. -func gatherForks(config *params.ChainConfig) ([]uint64, []uint64) { +func gatherForks(config *params.ChainConfig, genesis uint64) ([]uint64, []uint64) { // Gather all the fork block numbers via reflection kind := reflect.TypeOf(params.ChainConfig{}) conf := reflect.ValueOf(config).Elem() @@ -270,8 +269,8 @@ func gatherForks(config *params.ChainConfig) ([]uint64, []uint64) { } } } - sort.Slice(forksByBlock, func(i, j int) bool { return forksByBlock[i] < forksByBlock[j] }) - sort.Slice(forksByTime, func(i, j int) bool { return forksByTime[i] < forksByTime[j] }) + slices.Sort(forksByBlock) + slices.Sort(forksByTime) // Deduplicate fork identifiers applying multiple forks for i := 1; i < len(forksByBlock); i++ { @@ -290,7 +289,8 @@ func gatherForks(config *params.ChainConfig) ([]uint64, []uint64) { if len(forksByBlock) > 0 && forksByBlock[0] == 0 { forksByBlock = forksByBlock[1:] } - if len(forksByTime) > 0 && forksByTime[0] == 0 { + // Skip any forks before genesis. + for len(forksByTime) > 0 && forksByTime[0] <= genesis { forksByTime = forksByTime[1:] } return forksByBlock, forksByTime diff --git a/core/forkid/forkid_test.go b/core/forkid/forkid_test.go index ab59a454d8..3d49b2eced 100644 --- a/core/forkid/forkid_test.go +++ b/core/forkid/forkid_test.go @@ -18,10 +18,14 @@ package forkid import ( "bytes" + "hash/crc32" "math" + "math/big" "testing" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" ) @@ -36,13 +40,13 @@ func TestCreation(t *testing.T) { } tests := []struct { config *params.ChainConfig - genesis common.Hash + genesis *types.Block cases []testcase }{ // Mainnet test cases { params.MainnetChainConfig, - params.MainnetGenesisHash, + core.DefaultGenesisBlock().ToBlock(), []testcase{ {0, 0, ID{Hash: checksumToBytes(0xfc64ec04), Next: 1150000}}, // Unsynced {1149999, 0, ID{Hash: checksumToBytes(0xfc64ec04), Next: 1150000}}, // Last Frontier block @@ -74,34 +78,10 @@ func TestCreation(t *testing.T) { {30000000, 2000000000, ID{Hash: checksumToBytes(0xdce96c2d), Next: 0}}, // Future Shanghai block }, }, - // Rinkeby test cases - { - params.RinkebyChainConfig, - params.RinkebyGenesisHash, - []testcase{ - {0, 0, ID{Hash: checksumToBytes(0x3b8e0691), Next: 1}}, // Unsynced, last Frontier block - {1, 0, ID{Hash: checksumToBytes(0x60949295), Next: 2}}, // First and last Homestead block - {2, 0, ID{Hash: checksumToBytes(0x8bde40dd), Next: 3}}, // First and last Tangerine block - {3, 0, ID{Hash: checksumToBytes(0xcb3a64bb), Next: 1035301}}, // First Spurious block - {1035300, 0, ID{Hash: checksumToBytes(0xcb3a64bb), Next: 1035301}}, // Last Spurious block - {1035301, 0, ID{Hash: checksumToBytes(0x8d748b57), Next: 3660663}}, // First Byzantium block - {3660662, 0, ID{Hash: checksumToBytes(0x8d748b57), Next: 3660663}}, // Last Byzantium block - {3660663, 0, ID{Hash: checksumToBytes(0xe49cab14), Next: 4321234}}, // First Constantinople block - {4321233, 0, ID{Hash: checksumToBytes(0xe49cab14), Next: 4321234}}, // Last Constantinople block - {4321234, 0, ID{Hash: checksumToBytes(0xafec6b27), Next: 5435345}}, // First Petersburg block - {5435344, 0, ID{Hash: checksumToBytes(0xafec6b27), Next: 5435345}}, // Last Petersburg block - {5435345, 0, ID{Hash: checksumToBytes(0xcbdb8838), Next: 8290928}}, // First Istanbul block - {8290927, 0, ID{Hash: checksumToBytes(0xcbdb8838), Next: 8290928}}, // Last Istanbul block - {8290928, 0, ID{Hash: checksumToBytes(0x6910c8bd), Next: 8897988}}, // First Berlin block - {8897987, 0, ID{Hash: checksumToBytes(0x6910c8bd), Next: 8897988}}, // Last Berlin block - {8897988, 0, ID{Hash: checksumToBytes(0x8E29F2F3), Next: 0}}, // First London block - {10000000, 0, ID{Hash: checksumToBytes(0x8E29F2F3), Next: 0}}, // Future London block - }, - }, // Goerli test cases { params.GoerliChainConfig, - params.GoerliGenesisHash, + 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 @@ -118,7 +98,7 @@ func TestCreation(t *testing.T) { // Sepolia test cases { params.SepoliaChainConfig, - params.SepoliaGenesisHash, + core.DefaultSepoliaGenesisBlock().ToBlock(), []testcase{ {0, 0, ID{Hash: checksumToBytes(0xfe3366e7), Next: 1735371}}, // Unsynced, last Frontier, Homestead, Tangerine, Spurious, Byzantium, Constantinople, Petersburg, Istanbul, Berlin and first London block {1735370, 0, ID{Hash: checksumToBytes(0xfe3366e7), Next: 1735371}}, // Last London block @@ -377,7 +357,7 @@ func TestValidation(t *testing.T) { //{params.MainnetChainConfig, 20999999, 1677999999, ID{Hash: checksumToBytes(0x71147644), Next: 1678000000}, ErrLocalIncompatibleOrStale}, } for i, tt := range tests { - filter := newFilter(tt.config, params.MainnetGenesisHash, func() (uint64, uint64) { return tt.head, tt.time }) + filter := newFilter(tt.config, core.DefaultGenesisBlock().ToBlock(), func() (uint64, uint64) { return tt.head, tt.time }) if err := filter(tt.id); err != tt.err { t.Errorf("test %d: validation error mismatch: have %v, want %v", i, err, tt.err) } @@ -406,3 +386,55 @@ func TestEncoding(t *testing.T) { } } } + +// Tests that time-based forks which are active at genesis are not included in +// forkid hash. +func TestTimeBasedForkInGenesis(t *testing.T) { + var ( + time = uint64(1690475657) + genesis = types.NewBlockWithHeader(&types.Header{Time: time}) + forkidHash = checksumToBytes(crc32.ChecksumIEEE(genesis.Hash().Bytes())) + config = func(shanghai, cancun uint64) *params.ChainConfig { + return ¶ms.ChainConfig{ + ChainID: big.NewInt(1337), + 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(0), + MuirGlacierBlock: big.NewInt(0), + BerlinBlock: big.NewInt(0), + LondonBlock: big.NewInt(0), + TerminalTotalDifficulty: big.NewInt(0), + TerminalTotalDifficultyPassed: true, + MergeNetsplitBlock: big.NewInt(0), + ShanghaiTime: &shanghai, + CancunTime: &cancun, + Ethash: new(params.EthashConfig), + } + } + ) + tests := []struct { + config *params.ChainConfig + want ID + }{ + // Shanghai active before genesis, skip + {config(time-1, time+1), ID{Hash: forkidHash, Next: time + 1}}, + + // Shanghai active at genesis, skip + {config(time, time+1), ID{Hash: forkidHash, Next: time + 1}}, + + // Shanghai not active, skip + {config(time+1, time+2), ID{Hash: forkidHash, Next: time + 1}}, + } + for _, tt := range tests { + if have := NewID(tt.config, genesis, 0, time); have != tt.want { + t.Fatalf("incorrect forkid hash: have %x, want %x", have, tt.want) + } + } +} diff --git a/core/gen_genesis.go b/core/gen_genesis.go index 4e0844e889..38614252a3 100644 --- a/core/gen_genesis.go +++ b/core/gen_genesis.go @@ -18,19 +18,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"` - Alloc map[common.UnprefixedAddress]GenesisAccount `json:"alloc" gencodec:"required"` - Number math.HexOrDecimal64 `json:"number"` - GasUsed math.HexOrDecimal64 `json:"gasUsed"` - ParentHash common.Hash `json:"parentHash"` - BaseFee *math.HexOrDecimal256 `json:"baseFeePerGas"` + 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]GenesisAccount `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"` } var enc Genesis enc.Config = g.Config @@ -51,25 +53,29 @@ func (g Genesis) MarshalJSON() ([]byte, error) { enc.GasUsed = math.HexOrDecimal64(g.GasUsed) enc.ParentHash = g.ParentHash enc.BaseFee = (*math.HexOrDecimal256)(g.BaseFee) + enc.ExcessBlobGas = (*math.HexOrDecimal64)(g.ExcessBlobGas) + enc.BlobGasUsed = (*math.HexOrDecimal64)(g.BlobGasUsed) return json.Marshal(&enc) } // 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"` - Alloc map[common.UnprefixedAddress]GenesisAccount `json:"alloc" gencodec:"required"` - Number *math.HexOrDecimal64 `json:"number"` - GasUsed *math.HexOrDecimal64 `json:"gasUsed"` - ParentHash *common.Hash `json:"parentHash"` - BaseFee *math.HexOrDecimal256 `json:"baseFeePerGas"` + 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]GenesisAccount `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"` } var dec Genesis if err := json.Unmarshal(input, &dec); err != nil { @@ -120,5 +126,11 @@ func (g *Genesis) UnmarshalJSON(input []byte) error { if dec.BaseFee != nil { g.BaseFee = (*big.Int)(dec.BaseFee) } + if dec.ExcessBlobGas != nil { + g.ExcessBlobGas = (*uint64)(dec.ExcessBlobGas) + } + if dec.BlobGasUsed != nil { + g.BlobGasUsed = (*uint64)(dec.BlobGasUsed) + } return nil } diff --git a/core/genesis.go b/core/genesis.go index 26f31c0863..86a3e42a62 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -59,10 +59,12 @@ type Genesis struct { // These fields are used for consensus tests. Please don't use them // in actual genesis blocks. - Number uint64 `json:"number"` - GasUsed uint64 `json:"gasUsed"` - ParentHash common.Hash `json:"parentHash"` - BaseFee *big.Int `json:"baseFeePerGas"` + Number uint64 `json:"number"` + GasUsed uint64 `json:"gasUsed"` + ParentHash common.Hash `json:"parentHash"` + BaseFee *big.Int `json:"baseFeePerGas"` // EIP-1559 + ExcessBlobGas *uint64 `json:"excessBlobGas"` // EIP-4844 + BlobGasUsed *uint64 `json:"blobGasUsed"` // EIP-4844 } func ReadGenesis(db ethdb.Database) (*Genesis, error) { @@ -73,7 +75,7 @@ func ReadGenesis(db ethdb.Database) (*Genesis, error) { } blob := rawdb.ReadGenesisStateSpec(db, stored) if blob == nil { - return nil, fmt.Errorf("genesis state missing from db") + return nil, errors.New("genesis state missing from db") } if len(blob) != 0 { if err := genesis.Alloc.UnmarshalJSON(blob); err != nil { @@ -82,11 +84,11 @@ func ReadGenesis(db ethdb.Database) (*Genesis, error) { } genesis.Config = rawdb.ReadChainConfig(db, stored) if genesis.Config == nil { - return nil, fmt.Errorf("genesis config missing from db") + return nil, errors.New("genesis config missing from db") } genesisBlock := rawdb.ReadBlock(db, stored, 0) if genesisBlock == nil { - return nil, fmt.Errorf("genesis block missing from db") + return nil, errors.New("genesis block missing from db") } genesisHeader := genesisBlock.Header() genesis.Nonce = genesisHeader.Nonce.Uint64() @@ -96,6 +98,9 @@ func ReadGenesis(db ethdb.Database) (*Genesis, error) { genesis.Difficulty = genesisHeader.Difficulty genesis.Mixhash = genesisHeader.MixDigest genesis.Coinbase = genesisHeader.Coinbase + genesis.BaseFee = genesisHeader.BaseFee + genesis.ExcessBlobGas = genesisHeader.ExcessBlobGas + genesis.BlobGasUsed = genesisHeader.BlobGasUsed return &genesis, nil } @@ -125,14 +130,16 @@ func (ga *GenesisAlloc) deriveHash() (common.Hash, error) { return common.Hash{}, err } for addr, account := range *ga { - statedb.AddBalance(addr, account.Balance) + if account.Balance != nil { + statedb.AddBalance(addr, account.Balance) + } statedb.SetCode(addr, account.Code) statedb.SetNonce(addr, account.Nonce) for key, value := range account.Storage { statedb.SetState(addr, key, value) } } - return statedb.Commit(false) + return statedb.Commit(0, false) } // flush is very similar with deriveHash, but the main difference is @@ -144,14 +151,16 @@ func (ga *GenesisAlloc) flush(db ethdb.Database, triedb *trie.Database, blockhas return err } for addr, account := range *ga { - statedb.AddBalance(addr, account.Balance) + if account.Balance != nil { + statedb.AddBalance(addr, account.Balance) + } statedb.SetCode(addr, account.Code) statedb.SetNonce(addr, account.Nonce) for key, value := range account.Storage { statedb.SetState(addr, key, value) } } - root, err := statedb.Commit(false) + root, err := statedb.Commit(0, false) if err != nil { return err } @@ -189,8 +198,6 @@ func CommitGenesisState(db ethdb.Database, triedb *trie.Database, blockhash comm switch blockhash { case params.MainnetGenesisHash: genesis = DefaultGenesisBlock() - case params.RinkebyGenesisHash: - genesis = DefaultRinkebyGenesisBlock() case params.GoerliGenesisHash: genesis = DefaultGoerliGenesisBlock() case params.SepoliaGenesisHash: @@ -216,15 +223,17 @@ type GenesisAccount struct { // field type overrides for gencodec type genesisSpecMarshaling struct { - Nonce math.HexOrDecimal64 - Timestamp math.HexOrDecimal64 - ExtraData hexutil.Bytes - GasLimit math.HexOrDecimal64 - GasUsed math.HexOrDecimal64 - Number math.HexOrDecimal64 - Difficulty *math.HexOrDecimal256 - BaseFee *math.HexOrDecimal256 - Alloc map[common.UnprefixedAddress]GenesisAccount + Nonce math.HexOrDecimal64 + Timestamp math.HexOrDecimal64 + ExtraData hexutil.Bytes + GasLimit math.HexOrDecimal64 + GasUsed math.HexOrDecimal64 + Number math.HexOrDecimal64 + Difficulty *math.HexOrDecimal256 + Alloc map[common.UnprefixedAddress]GenesisAccount + BaseFee *math.HexOrDecimal256 + ExcessBlobGas *math.HexOrDecimal64 + BlobGasUsed *math.HexOrDecimal64 } type genesisAccountMarshaling struct { @@ -268,6 +277,7 @@ func (e *GenesisMismatchError) Error() string { // ChainOverrides contains the changes to chain config. type ChainOverrides struct { OverrideCancun *uint64 + OverrideVerkle *uint64 } // SetupGenesisBlock writes or updates the genesis block in db. @@ -296,6 +306,9 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *trie.Database, gen if overrides != nil && overrides.OverrideCancun != nil { config.CancunTime = overrides.OverrideCancun } + if overrides != nil && overrides.OverrideVerkle != nil { + config.VerkleTime = overrides.OverrideVerkle + } } } // Just commit the new block if there is no stored genesis block. @@ -314,10 +327,12 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *trie.Database, gen applyOverrides(genesis.Config) return genesis.Config, block.Hash(), nil } - // We have the genesis block in database(perhaps in ancient database) - // but the corresponding state is missing. + // The genesis block is present(perhaps in ancient database) while the + // state database is not initialized yet. It can happen that the node + // is initialized with an external ancient store. Commit genesis state + // in this case. header := rawdb.ReadHeader(db, stored, 0) - if header.Root != types.EmptyRootHash && !rawdb.HasLegacyTrieNode(db, header.Root) { + if header.Root != types.EmptyRootHash && !triedb.Initialized(header.Root) { if genesis == nil { genesis = DefaultGenesisBlock() } @@ -366,7 +381,7 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *trie.Database, gen // are returned to the caller unless we're already at block zero. head := rawdb.ReadHeadHeader(db) if head == nil { - return newcfg, stored, fmt.Errorf("missing head header") + return newcfg, stored, errors.New("missing head header") } compatErr := storedcfg.CheckCompatible(newcfg, head.Number.Uint64(), head.Time) if compatErr != nil && ((head.Number.Uint64() != 0 && compatErr.RewindToBlock != 0) || (head.Time != 0 && compatErr.RewindToTime != 0)) { @@ -420,8 +435,6 @@ func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig { return params.MainnetChainConfig case ghash == params.SepoliaGenesisHash: return params.SepoliaChainConfig - case ghash == params.RinkebyGenesisHash: - return params.RinkebyChainConfig case ghash == params.GoerliGenesisHash: return params.GoerliChainConfig default: @@ -463,9 +476,27 @@ func (g *Genesis) ToBlock() *types.Block { } } var withdrawals []*types.Withdrawal - if g.Config != nil && g.Config.IsShanghai(g.Timestamp) { - head.WithdrawalsHash = &types.EmptyWithdrawalsHash - withdrawals = make([]*types.Withdrawal, 0) + if conf := g.Config; conf != nil { + num := big.NewInt(int64(g.Number)) + if conf.IsShanghai(num, g.Timestamp) { + head.WithdrawalsHash = &types.EmptyWithdrawalsHash + withdrawals = make([]*types.Withdrawal, 0) + } + if conf.IsCancun(num, g.Timestamp) { + // EIP-4788: The parentBeaconBlockRoot of the genesis block is always + // the zero hash. This is because the genesis block does not have a parent + // by definition. + head.ParentBeaconRoot = new(common.Hash) + // EIP-4844 fields + head.ExcessBlobGas = g.ExcessBlobGas + head.BlobGasUsed = g.BlobGasUsed + if head.ExcessBlobGas == nil { + head.ExcessBlobGas = new(uint64) + } + if head.BlobGasUsed == nil { + head.BlobGasUsed = new(uint64) + } + } } return types.NewBlock(head, nil, nil, nil, trie.NewStackTrie(nil)).WithWithdrawals(withdrawals) } @@ -506,10 +537,8 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *trie.Database) (*types.Block // MustCommit writes the genesis block and state to db, panicking on error. // The block is committed as the canonical head block. -// Note the state changes will be committed in hash-based scheme, use Commit -// if path-scheme is preferred. -func (g *Genesis) MustCommit(db ethdb.Database) *types.Block { - block, err := g.Commit(db, trie.NewDatabase(db)) +func (g *Genesis) MustCommit(db ethdb.Database, triedb *trie.Database) *types.Block { + block, err := g.Commit(db, triedb) if err != nil { panic(err) } @@ -528,18 +557,6 @@ func DefaultGenesisBlock() *Genesis { } } -// DefaultRinkebyGenesisBlock returns the Rinkeby network genesis block. -func DefaultRinkebyGenesisBlock() *Genesis { - return &Genesis{ - Config: params.RinkebyChainConfig, - Timestamp: 1492009146, - ExtraData: hexutil.MustDecode("0x52657370656374206d7920617574686f7269746168207e452e436172746d616e42eb768f2244c8811c63729a21a3569731535f067ffc57839b00206d1ad20c69a1981b489f772031b279182d99e65703f0076e4812653aab85fca0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), - GasLimit: 4700000, - Difficulty: big.NewInt(1), - Alloc: decodePrealloc(rinkebyAllocData), - } -} - // DefaultGoerliGenesisBlock returns the Görli network genesis block. func DefaultGoerliGenesisBlock() *Genesis { return &Genesis{ @@ -565,22 +582,30 @@ func DefaultSepoliaGenesisBlock() *Genesis { } } -// DeveloperGenesisBlock returns the 'geth --dev' genesis block. -func DeveloperGenesisBlock(period uint64, gasLimit uint64, faucet common.Address) *Genesis { - // Override the default period to the user requested one - config := *params.AllCliqueProtocolChanges - config.Clique = ¶ms.CliqueConfig{ - Period: period, - Epoch: config.Clique.Epoch, +// DefaultHoleskyGenesisBlock returns the Holesky network genesis block. +func DefaultHoleskyGenesisBlock() *Genesis { + return &Genesis{ + Config: params.HoleskyChainConfig, + Nonce: 0x1234, + ExtraData: hexutil.MustDecode("0x686f77206d7563682069732074686520666973683f"), + GasLimit: 0x17d7840, + Difficulty: big.NewInt(0x01), + Timestamp: 1694786100, + Alloc: decodePrealloc(holeskyAllocData), } +} + +// DeveloperGenesisBlock returns the 'geth --dev' genesis block. +func DeveloperGenesisBlock(gasLimit uint64, faucet common.Address) *Genesis { + // Override the default period to the user requested one + config := *params.AllDevChainProtocolChanges // Assemble and return the genesis with the precompiles and faucet pre-funded return &Genesis{ Config: &config, - ExtraData: append(append(make([]byte, 32), faucet[:]...), make([]byte, crypto.SignatureLength)...), GasLimit: gasLimit, BaseFee: big.NewInt(params.InitialBaseFee), - Difficulty: big.NewInt(1), + Difficulty: big.NewInt(0), Alloc: map[common.Address]GenesisAccount{ common.BytesToAddress([]byte{1}): {Balance: big.NewInt(1)}, // ECRecover common.BytesToAddress([]byte{2}): {Balance: big.NewInt(1)}, // SHA256 @@ -597,13 +622,34 @@ func DeveloperGenesisBlock(period uint64, gasLimit uint64, faucet common.Address } func decodePrealloc(data string) GenesisAlloc { - var p []struct{ Addr, Balance *big.Int } + var p []struct { + Addr *big.Int + Balance *big.Int + Misc *struct { + Nonce uint64 + Code []byte + Slots []struct { + Key common.Hash + Val common.Hash + } + } `rlp:"optional"` + } if err := rlp.NewStream(strings.NewReader(data), 0).Decode(&p); err != nil { panic(err) } ga := make(GenesisAlloc, len(p)) for _, account := range p { - ga[common.BigToAddress(account.Addr)] = GenesisAccount{Balance: account.Balance} + acc := GenesisAccount{Balance: account.Balance} + if account.Misc != nil { + acc.Nonce = account.Misc.Nonce + acc.Code = account.Misc.Code + + acc.Storage = make(map[common.Hash]common.Hash) + for _, slot := range account.Misc.Slots { + acc.Storage[slot.Key] = slot.Val + } + } + ga[common.BigToAddress(account.Addr)] = acc } return ga } diff --git a/core/genesis_alloc.go b/core/genesis_alloc.go index 542dcc4120..94c4ec5358 100644 --- a/core/genesis_alloc.go +++ b/core/genesis_alloc.go @@ -22,871 +22,6 @@ 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\xf6\x941\xb9\x8d\x14\x00{\xde\xe67)\x80\x86\x98\x8a\v\xbd1\x18E#\xa0\x02\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" const goerliAllocData = "\xf9\x04\x06\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\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 KilnAllocData = `{ - "config": { - "chainId": 1337802, - "homesteadBlock": 0, - "eip150Block": 0, - "eip155Block": 0, - "eip158Block": 0, - "byzantiumBlock": 0, - "constantinopleBlock": 0, - "petersburgBlock": 0, - "istanbulBlock": 0, - "berlinBlock": 0, - "londonBlock": 0, - "mergeForkBlock": 1000, - "terminalTotalDifficulty": 20000000000000 - }, - "alloc": { - "0x0000000000000000000000000000000000000000": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000001": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000002": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000003": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000004": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000005": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000006": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000007": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000008": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000009": { - "balance": "1" - }, - "0x000000000000000000000000000000000000000a": { - "balance": "1" - }, - "0x000000000000000000000000000000000000000b": { - "balance": "1" - }, - "0x000000000000000000000000000000000000000c": { - "balance": "1" - }, - "0x000000000000000000000000000000000000000d": { - "balance": "1" - }, - "0x000000000000000000000000000000000000000e": { - "balance": "1" - }, - "0x000000000000000000000000000000000000000f": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000010": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000011": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000012": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000013": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000014": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000015": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000016": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000017": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000018": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000019": { - "balance": "1" - }, - "0x000000000000000000000000000000000000001a": { - "balance": "1" - }, - "0x000000000000000000000000000000000000001b": { - "balance": "1" - }, - "0x000000000000000000000000000000000000001c": { - "balance": "1" - }, - "0x000000000000000000000000000000000000001d": { - "balance": "1" - }, - "0x000000000000000000000000000000000000001e": { - "balance": "1" - }, - "0x000000000000000000000000000000000000001f": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000020": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000021": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000022": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000023": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000024": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000025": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000026": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000027": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000028": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000029": { - "balance": "1" - }, - "0x000000000000000000000000000000000000002a": { - "balance": "1" - }, - "0x000000000000000000000000000000000000002b": { - "balance": "1" - }, - "0x000000000000000000000000000000000000002c": { - "balance": "1" - }, - "0x000000000000000000000000000000000000002d": { - "balance": "1" - }, - "0x000000000000000000000000000000000000002e": { - "balance": "1" - }, - "0x000000000000000000000000000000000000002f": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000030": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000031": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000032": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000033": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000034": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000035": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000036": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000037": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000038": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000039": { - "balance": "1" - }, - "0x000000000000000000000000000000000000003a": { - "balance": "1" - }, - "0x000000000000000000000000000000000000003b": { - "balance": "1" - }, - "0x000000000000000000000000000000000000003c": { - "balance": "1" - }, - "0x000000000000000000000000000000000000003d": { - "balance": "1" - }, - "0x000000000000000000000000000000000000003e": { - "balance": "1" - }, - "0x000000000000000000000000000000000000003f": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000040": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000041": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000042": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000043": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000044": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000045": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000046": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000047": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000048": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000049": { - "balance": "1" - }, - "0x000000000000000000000000000000000000004a": { - "balance": "1" - }, - "0x000000000000000000000000000000000000004b": { - "balance": "1" - }, - "0x000000000000000000000000000000000000004c": { - "balance": "1" - }, - "0x000000000000000000000000000000000000004d": { - "balance": "1" - }, - "0x000000000000000000000000000000000000004e": { - "balance": "1" - }, - "0x000000000000000000000000000000000000004f": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000050": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000051": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000052": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000053": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000054": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000055": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000056": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000057": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000058": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000059": { - "balance": "1" - }, - "0x000000000000000000000000000000000000005a": { - "balance": "1" - }, - "0x000000000000000000000000000000000000005b": { - "balance": "1" - }, - "0x000000000000000000000000000000000000005c": { - "balance": "1" - }, - "0x000000000000000000000000000000000000005d": { - "balance": "1" - }, - "0x000000000000000000000000000000000000005e": { - "balance": "1" - }, - "0x000000000000000000000000000000000000005f": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000060": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000061": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000062": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000063": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000064": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000065": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000066": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000067": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000068": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000069": { - "balance": "1" - }, - "0x000000000000000000000000000000000000006a": { - "balance": "1" - }, - "0x000000000000000000000000000000000000006b": { - "balance": "1" - }, - "0x000000000000000000000000000000000000006c": { - "balance": "1" - }, - "0x000000000000000000000000000000000000006d": { - "balance": "1" - }, - "0x000000000000000000000000000000000000006e": { - "balance": "1" - }, - "0x000000000000000000000000000000000000006f": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000070": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000071": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000072": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000073": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000074": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000075": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000076": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000077": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000078": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000079": { - "balance": "1" - }, - "0x000000000000000000000000000000000000007a": { - "balance": "1" - }, - "0x000000000000000000000000000000000000007b": { - "balance": "1" - }, - "0x000000000000000000000000000000000000007c": { - "balance": "1" - }, - "0x000000000000000000000000000000000000007d": { - "balance": "1" - }, - "0x000000000000000000000000000000000000007e": { - "balance": "1" - }, - "0x000000000000000000000000000000000000007f": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000080": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000081": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000082": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000083": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000084": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000085": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000086": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000087": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000088": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000089": { - "balance": "1" - }, - "0x000000000000000000000000000000000000008a": { - "balance": "1" - }, - "0x000000000000000000000000000000000000008b": { - "balance": "1" - }, - "0x000000000000000000000000000000000000008c": { - "balance": "1" - }, - "0x000000000000000000000000000000000000008d": { - "balance": "1" - }, - "0x000000000000000000000000000000000000008e": { - "balance": "1" - }, - "0x000000000000000000000000000000000000008f": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000090": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000091": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000092": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000093": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000094": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000095": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000096": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000097": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000098": { - "balance": "1" - }, - "0x0000000000000000000000000000000000000099": { - "balance": "1" - }, - "0x000000000000000000000000000000000000009a": { - "balance": "1" - }, - "0x000000000000000000000000000000000000009b": { - "balance": "1" - }, - "0x000000000000000000000000000000000000009c": { - "balance": "1" - }, - "0x000000000000000000000000000000000000009d": { - "balance": "1" - }, - "0x000000000000000000000000000000000000009e": { - "balance": "1" - }, - "0x000000000000000000000000000000000000009f": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000a0": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000a1": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000a2": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000a3": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000a4": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000a5": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000a6": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000a7": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000a8": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000a9": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000aa": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000ab": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000ac": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000ad": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000ae": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000af": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000b0": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000b1": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000b2": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000b3": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000b4": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000b5": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000b6": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000b7": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000b8": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000b9": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000ba": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000bb": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000bc": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000bd": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000be": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000bf": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000c0": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000c1": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000c2": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000c3": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000c4": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000c5": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000c6": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000c7": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000c8": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000c9": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000ca": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000cb": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000cc": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000cd": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000ce": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000cf": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000d0": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000d1": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000d2": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000d3": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000d4": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000d5": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000d6": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000d7": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000d8": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000d9": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000da": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000db": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000dc": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000dd": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000de": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000df": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000e0": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000e1": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000e2": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000e3": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000e4": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000e5": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000e6": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000e7": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000e8": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000e9": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000ea": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000eb": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000ec": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000ed": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000ee": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000ef": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000f0": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000f1": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000f2": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000f3": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000f4": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000f5": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000f6": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000f7": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000f8": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000f9": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000fa": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000fb": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000fc": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000fd": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000fe": { - "balance": "1" - }, - "0x00000000000000000000000000000000000000ff": { - "balance": "1" - }, - "0x4242424242424242424242424242424242424242": { - "balance": "0", - "code": "0x60806040526004361061003f5760003560e01c806301ffc9a71461004457806322895118146100a4578063621fd130146101ba578063c5f2892f14610244575b600080fd5b34801561005057600080fd5b506100906004803603602081101561006757600080fd5b50357fffffffff000000000000000000000000000000000000000000000000000000001661026b565b604080519115158252519081900360200190f35b6101b8600480360360808110156100ba57600080fd5b8101906020810181356401000000008111156100d557600080fd5b8201836020820111156100e757600080fd5b8035906020019184600183028401116401000000008311171561010957600080fd5b91939092909160208101903564010000000081111561012757600080fd5b82018360208201111561013957600080fd5b8035906020019184600183028401116401000000008311171561015b57600080fd5b91939092909160208101903564010000000081111561017957600080fd5b82018360208201111561018b57600080fd5b803590602001918460018302840111640100000000831117156101ad57600080fd5b919350915035610304565b005b3480156101c657600080fd5b506101cf6110b5565b6040805160208082528351818301528351919283929083019185019080838360005b838110156102095781810151838201526020016101f1565b50505050905090810190601f1680156102365780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561025057600080fd5b506102596110c7565b60408051918252519081900360200190f35b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a70000000000000000000000000000000000000000000000000000000014806102fe57507fffffffff0000000000000000000000000000000000000000000000000000000082167f8564090700000000000000000000000000000000000000000000000000000000145b92915050565b6030861461035d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118056026913960400191505060405180910390fd5b602084146103b6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603681526020018061179c6036913960400191505060405180910390fd5b6060821461040f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260298152602001806118786029913960400191505060405180910390fd5b670de0b6b3a7640000341015610470576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118526026913960400191505060405180910390fd5b633b9aca003406156104cd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260338152602001806117d26033913960400191505060405180910390fd5b633b9aca00340467ffffffffffffffff811115610535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602781526020018061182b6027913960400191505060405180910390fd5b6060610540826114ba565b90507f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c589898989858a8a6105756020546114ba565b6040805160a0808252810189905290819060208201908201606083016080840160c085018e8e80828437600083820152601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690910187810386528c815260200190508c8c808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690920188810386528c5181528c51602091820193918e019250908190849084905b83811015610648578181015183820152602001610630565b50505050905090810190601f1680156106755780820380516001836020036101000a031916815260200191505b5086810383528881526020018989808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169092018881038452895181528951602091820193918b019250908190849084905b838110156106ef5781810151838201526020016106d7565b50505050905090810190601f16801561071c5780820380516001836020036101000a031916815260200191505b509d505050505050505050505050505060405180910390a1600060028a8a600060801b604051602001808484808284377fffffffffffffffffffffffffffffffff0000000000000000000000000000000090941691909301908152604080517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0818403018152601090920190819052815191955093508392506020850191508083835b602083106107fc57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016107bf565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610859573d6000803e3d6000fd5b5050506040513d602081101561086e57600080fd5b5051905060006002806108846040848a8c6116fe565b6040516020018083838082843780830192505050925050506040516020818303038152906040526040518082805190602001908083835b602083106108f857805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016108bb565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610955573d6000803e3d6000fd5b5050506040513d602081101561096a57600080fd5b5051600261097b896040818d6116fe565b60405160009060200180848480828437919091019283525050604080518083038152602092830191829052805190945090925082918401908083835b602083106109f457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016109b7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610a51573d6000803e3d6000fd5b5050506040513d6020811015610a6657600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610ada57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610a9d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610b37573d6000803e3d6000fd5b5050506040513d6020811015610b4c57600080fd5b50516040805160208101858152929350600092600292839287928f928f92018383808284378083019250505093505050506040516020818303038152906040526040518082805190602001908083835b60208310610bd957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610b9c565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610c36573d6000803e3d6000fd5b5050506040513d6020811015610c4b57600080fd5b50516040518651600291889160009188916020918201918291908601908083835b60208310610ca957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610c6c565b6001836020036101000a0380198251168184511680821785525050505050509050018367ffffffffffffffff191667ffffffffffffffff1916815260180182815260200193505050506040516020818303038152906040526040518082805190602001908083835b60208310610d4e57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610d11565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610dab573d6000803e3d6000fd5b5050506040513d6020811015610dc057600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610e3457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610df7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610e91573d6000803e3d6000fd5b5050506040513d6020811015610ea657600080fd5b50519050858114610f02576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260548152602001806117486054913960600191505060405180910390fd5b60205463ffffffff11610f60576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806117276021913960400191505060405180910390fd5b602080546001019081905560005b60208110156110a9578160011660011415610fa0578260008260208110610f9157fe5b0155506110ac95505050505050565b600260008260208110610faf57fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061102557805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610fe8565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015611082573d6000803e3d6000fd5b5050506040513d602081101561109757600080fd5b50519250600282049150600101610f6e565b50fe5b50505050505050565b60606110c26020546114ba565b905090565b6020546000908190815b60208110156112f05781600116600114156111e6576002600082602081106110f557fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061116b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161112e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156111c8573d6000803e3d6000fd5b5050506040513d60208110156111dd57600080fd5b505192506112e2565b600283602183602081106111f657fe5b015460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061126b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161122e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156112c8573d6000803e3d6000fd5b5050506040513d60208110156112dd57600080fd5b505192505b6002820491506001016110d1565b506002826112ff6020546114ba565b600060401b6040516020018084815260200183805190602001908083835b6020831061135a57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161131d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790527fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000095909516920191825250604080518083037ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8018152601890920190819052815191955093508392850191508083835b6020831061143f57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101611402565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa15801561149c573d6000803e3d6000fd5b5050506040513d60208110156114b157600080fd5b50519250505090565b60408051600880825281830190925260609160208201818036833701905050905060c082901b8060071a60f81b826000815181106114f457fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060061a60f81b8260018151811061153757fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060051a60f81b8260028151811061157a57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060041a60f81b826003815181106115bd57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060031a60f81b8260048151811061160057fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060021a60f81b8260058151811061164357fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060011a60f81b8260068151811061168657fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060001a60f81b826007815181106116c957fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535050919050565b6000808585111561170d578182fd5b83861115611719578182fd5b505082019391909203915056fe4465706f736974436f6e74726163743a206d65726b6c6520747265652066756c6c4465706f736974436f6e74726163743a207265636f6e7374727563746564204465706f7369744461746120646f6573206e6f74206d6174636820737570706c696564206465706f7369745f646174615f726f6f744465706f736974436f6e74726163743a20696e76616c6964207769746864726177616c5f63726564656e7469616c73206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c7565206e6f74206d756c7469706c65206f6620677765694465706f736974436f6e74726163743a20696e76616c6964207075626b6579206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f20686967684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f206c6f774465706f736974436f6e74726163743a20696e76616c6964207369676e6174757265206c656e677468a26469706673582212201dd26f37a621703009abf16e77e69c93dc50c79db7f6cc37543e3e0e3decdc9764736f6c634300060b0033", - "storage": { - "0x0000000000000000000000000000000000000000000000000000000000000022": "0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b", - "0x0000000000000000000000000000000000000000000000000000000000000023": "0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71", - "0x0000000000000000000000000000000000000000000000000000000000000024": "0xc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c", - "0x0000000000000000000000000000000000000000000000000000000000000025": "0x536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123c", - "0x0000000000000000000000000000000000000000000000000000000000000026": "0x9efde052aa15429fae05bad4d0b1d7c64da64d03d7a1854a588c2cb8430c0d30", - "0x0000000000000000000000000000000000000000000000000000000000000027": "0xd88ddfeed400a8755596b21942c1497e114c302e6118290f91e6772976041fa1", - "0x0000000000000000000000000000000000000000000000000000000000000028": "0x87eb0ddba57e35f6d286673802a4af5975e22506c7cf4c64bb6be5ee11527f2c", - "0x0000000000000000000000000000000000000000000000000000000000000029": "0x26846476fd5fc54a5d43385167c95144f2643f533cc85bb9d16b782f8d7db193", - "0x000000000000000000000000000000000000000000000000000000000000002a": "0x506d86582d252405b840018792cad2bf1259f1ef5aa5f887e13cb2f0094f51e1", - "0x000000000000000000000000000000000000000000000000000000000000002b": "0xffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b", - "0x000000000000000000000000000000000000000000000000000000000000002c": "0x6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220", - "0x000000000000000000000000000000000000000000000000000000000000002d": "0xb7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f", - "0x000000000000000000000000000000000000000000000000000000000000002e": "0xdf6af5f5bbdb6be9ef8aa618e4bf8073960867171e29676f8b284dea6a08a85e", - "0x000000000000000000000000000000000000000000000000000000000000002f": "0xb58d900f5e182e3c50ef74969ea16c7726c549757cc23523c369587da7293784", - "0x0000000000000000000000000000000000000000000000000000000000000030": "0xd49a7502ffcfb0340b1d7885688500ca308161a7f96b62df9d083b71fcc8f2bb", - "0x0000000000000000000000000000000000000000000000000000000000000031": "0x8fe6b1689256c0d385f42f5bbe2027a22c1996e110ba97c171d3e5948de92beb", - "0x0000000000000000000000000000000000000000000000000000000000000032": "0x8d0d63c39ebade8509e0ae3c9c3876fb5fa112be18f905ecacfecb92057603ab", - "0x0000000000000000000000000000000000000000000000000000000000000033": "0x95eec8b2e541cad4e91de38385f2e046619f54496c2382cb6cacd5b98c26f5a4", - "0x0000000000000000000000000000000000000000000000000000000000000034": "0xf893e908917775b62bff23294dbbe3a1cd8e6cc1c35b4801887b646a6f81f17f", - "0x0000000000000000000000000000000000000000000000000000000000000035": "0xcddba7b592e3133393c16194fac7431abf2f5485ed711db282183c819e08ebaa", - "0x0000000000000000000000000000000000000000000000000000000000000036": "0x8a8d7fe3af8caa085a7639a832001457dfb9128a8061142ad0335629ff23ff9c", - "0x0000000000000000000000000000000000000000000000000000000000000037": "0xfeb3c337d7a51a6fbf00b9e34c52e1c9195c969bd4e7a0bfd51d5c5bed9c1167", - "0x0000000000000000000000000000000000000000000000000000000000000038": "0xe71f0aa83cc32edfbefa9f4d3e0174ca85182eec9f3a09f6a6c0df6377a510d7", - "0x0000000000000000000000000000000000000000000000000000000000000039": "0x31206fa80a50bb6abe29085058f16212212a60eec8f049fecb92d8c8e0a84bc0", - "0x000000000000000000000000000000000000000000000000000000000000003a": "0x21352bfecbeddde993839f614c3dac0a3ee37543f9b412b16199dc158e23b544", - "0x000000000000000000000000000000000000000000000000000000000000003b": "0x619e312724bb6d7c3153ed9de791d764a366b389af13c58bf8a8d90481a46765", - "0x000000000000000000000000000000000000000000000000000000000000003c": "0x7cdd2986268250628d0c10e385c58c6191e6fbe05191bcc04f133f2cea72c1c4", - "0x000000000000000000000000000000000000000000000000000000000000003d": "0x848930bd7ba8cac54661072113fb278869e07bb8587f91392933374d017bcbe1", - "0x000000000000000000000000000000000000000000000000000000000000003e": "0x8869ff2c22b28cc10510d9853292803328be4fb0e80495e8bb8d271f5b889636", - "0x000000000000000000000000000000000000000000000000000000000000003f": "0xb5fe28e79f1b850f8658246ce9b6a1e7b49fc06db7143e8fe0b4f2b0c5523a5c", - "0x0000000000000000000000000000000000000000000000000000000000000040": "0x985e929f70af28d0bdd1a90a808f977f597c7c778c489e98d3bd8910d31ac0f7" - } - }, - "0xf97e180c050e5Ab072211Ad2C213Eb5AEE4DF134": { - "balance": "10000000000000000000000000" - }, - "0x2cA5F489CC1Fd1CEC24747B64E8dE0F4A6A850E1": { - "balance": "10000000000000000000000000" - }, - "0x7203bd333a874D9d329050ecE393820fCD501eaA": { - "balance": "10000000000000000000000000" - }, - "0xA51918aA40D78Ff8be939bf0E8404252875c6aDF": { - "balance": "10000000000000000000000000" - }, - "0xAA81078e6b2121dd7A846690DFdD6b10d7658d8B": { - "balance": "10000000000000000000000000" - }, - "0xFA2d31D8f21c1D1633E9BEB641dF77D21D63ccDd": { - "balance": "10000000000000000000000000" - }, - "0xf751C9c6d60614226fE57D2cAD6e10C856a2ddA3": { - "balance": "10000000000000000000000000" - }, - "0x9cD16887f6A808AEaa65D3c840f059EeA4ca1319": { - "balance": "10000000000000000000000000" - }, - "0x2E07043584F11BFF0AC39c927665DF6c6ebaffFB": { - "balance": "10000000000000000000000000" - }, - "0x60e771E5eCA8E26690920de669520Da210D64A9B": { - "balance": "10000000000000000000000000" - }, - "0xFC4db92C2Cf77CE02fBfd7Da0346d2CbFA66aD59": { - "balance": "10000000000000000000000000" - } - }, - "coinbase": "0x0000000000000000000000000000000000000000", - "difficulty": "0x01", - "extraData": "", - "gasLimit": "0x400000", - "nonce": "0x1234", - "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "timestamp": "0" - }` +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 0e966bab03..6a0f2df085 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -30,18 +30,24 @@ import ( "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/trie" + "github.com/ethereum/go-ethereum/trie/triedb/pathdb" ) func TestInvalidCliqueConfig(t *testing.T) { block := DefaultGoerliGenesisBlock() block.ExtraData = []byte{} db := rawdb.NewMemoryDatabase() - if _, err := block.Commit(db, trie.NewDatabase(db)); err == nil { + if _, err := block.Commit(db, trie.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) +} + +func testSetupGenesis(t *testing.T, scheme string) { var ( customghash = common.HexToHash("0x89c99d90b79719238d2645c7642f2c9295246e80775b38cfd162b696817fbd50") customg = Genesis{ @@ -53,6 +59,7 @@ func TestSetupGenesis(t *testing.T) { oldcustomg = customg ) oldcustomg.Config = ¶ms.ChainConfig{HomesteadBlock: big.NewInt(2)} + tests := []struct { name string fn func(ethdb.Database) (*params.ChainConfig, common.Hash, error) @@ -63,7 +70,7 @@ func TestSetupGenesis(t *testing.T) { { name: "genesis without ChainConfig", fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { - return SetupGenesisBlock(db, trie.NewDatabase(db), new(Genesis)) + return SetupGenesisBlock(db, trie.NewDatabase(db, newDbConfig(scheme)), new(Genesis)) }, wantErr: errGenesisNoConfig, wantConfig: params.AllEthashProtocolChanges, @@ -71,7 +78,7 @@ func TestSetupGenesis(t *testing.T) { { name: "no block in DB, genesis == nil", fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { - return SetupGenesisBlock(db, trie.NewDatabase(db), nil) + return SetupGenesisBlock(db, trie.NewDatabase(db, newDbConfig(scheme)), nil) }, wantHash: params.MainnetGenesisHash, wantConfig: params.MainnetChainConfig, @@ -79,8 +86,8 @@ func TestSetupGenesis(t *testing.T) { { name: "mainnet block in DB, genesis == nil", fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { - DefaultGenesisBlock().MustCommit(db) - return SetupGenesisBlock(db, trie.NewDatabase(db), nil) + DefaultGenesisBlock().MustCommit(db, trie.NewDatabase(db, newDbConfig(scheme))) + return SetupGenesisBlock(db, trie.NewDatabase(db, newDbConfig(scheme)), nil) }, wantHash: params.MainnetGenesisHash, wantConfig: params.MainnetChainConfig, @@ -88,8 +95,9 @@ func TestSetupGenesis(t *testing.T) { { name: "custom block in DB, genesis == nil", fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { - customg.MustCommit(db) - return SetupGenesisBlock(db, trie.NewDatabase(db), nil) + tdb := trie.NewDatabase(db, newDbConfig(scheme)) + customg.Commit(db, tdb) + return SetupGenesisBlock(db, tdb, nil) }, wantHash: customghash, wantConfig: customg.Config, @@ -97,8 +105,9 @@ func TestSetupGenesis(t *testing.T) { { name: "custom block in DB, genesis == goerli", fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { - customg.MustCommit(db) - return SetupGenesisBlock(db, trie.NewDatabase(db), DefaultGoerliGenesisBlock()) + tdb := trie.NewDatabase(db, newDbConfig(scheme)) + customg.Commit(db, tdb) + return SetupGenesisBlock(db, tdb, DefaultGoerliGenesisBlock()) }, wantErr: &GenesisMismatchError{Stored: customghash, New: params.GoerliGenesisHash}, wantHash: params.GoerliGenesisHash, @@ -107,8 +116,9 @@ func TestSetupGenesis(t *testing.T) { { name: "compatible config in DB", fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { - oldcustomg.MustCommit(db) - return SetupGenesisBlock(db, trie.NewDatabase(db), &customg) + tdb := trie.NewDatabase(db, newDbConfig(scheme)) + oldcustomg.Commit(db, tdb) + return SetupGenesisBlock(db, tdb, &customg) }, wantHash: customghash, wantConfig: customg.Config, @@ -118,16 +128,17 @@ func TestSetupGenesis(t *testing.T) { fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { // Commit the 'old' genesis block with Homestead transition at #2. // Advance to block #4, past the homestead transition block of customg. - genesis := oldcustomg.MustCommit(db) + tdb := trie.NewDatabase(db, newDbConfig(scheme)) + oldcustomg.Commit(db, tdb) - bc, _ := NewBlockChain(db, nil, &oldcustomg, nil, ethash.NewFullFaker(), vm.Config{}, nil, nil) + bc, _ := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), &oldcustomg, nil, ethash.NewFullFaker(), vm.Config{}, nil, nil) defer bc.Stop() - blocks, _ := GenerateChain(oldcustomg.Config, genesis, ethash.NewFaker(), db, 4, nil) + _, blocks, _ := GenerateChainWithGenesis(&oldcustomg, ethash.NewFaker(), 4, nil) bc.InsertChain(blocks) // This should return a compatibility error. - return SetupGenesisBlock(db, trie.NewDatabase(db), &customg) + return SetupGenesisBlock(db, tdb, &customg) }, wantHash: customghash, wantConfig: customg.Config, @@ -172,11 +183,11 @@ func TestGenesisHashes(t *testing.T) { }{ {DefaultGenesisBlock(), params.MainnetGenesisHash}, {DefaultGoerliGenesisBlock(), params.GoerliGenesisHash}, - {DefaultRinkebyGenesisBlock(), params.RinkebyGenesisHash}, {DefaultSepoliaGenesisBlock(), params.SepoliaGenesisHash}, } { // Test via MustCommit - if have := c.genesis.MustCommit(rawdb.NewMemoryDatabase()).Hash(); have != c.want { + db := rawdb.NewMemoryDatabase() + if have := c.genesis.MustCommit(db, trie.NewDatabase(db, trie.HashDefaults)).Hash(); have != c.want { t.Errorf("case: %d a), want: %s, got: %s", i, c.want.Hex(), have.Hex()) } // Test via ToBlock @@ -194,7 +205,7 @@ func TestGenesis_Commit(t *testing.T) { } db := rawdb.NewMemoryDatabase() - genesisBlock := genesis.MustCommit(db) + genesisBlock := genesis.MustCommit(db, trie.NewDatabase(db, trie.HashDefaults)) if genesis.Difficulty != nil { t.Fatalf("assumption wrong") @@ -243,3 +254,10 @@ func TestReadWriteGenesisAlloc(t *testing.T) { } } } + +func newDbConfig(scheme string) *trie.Config { + if scheme == rawdb.HashScheme { + return trie.HashDefaults + } + return &trie.Config{PathDB: pathdb.Defaults} +} diff --git a/core/headerchain_test.go b/core/headerchain_test.go index 08d19f6950..2c0323e6f7 100644 --- a/core/headerchain_test.go +++ b/core/headerchain_test.go @@ -73,7 +73,7 @@ func TestHeaderInsertion(t *testing.T) { db = rawdb.NewMemoryDatabase() gspec = &Genesis{BaseFee: big.NewInt(params.InitialBaseFee), Config: params.AllEthashProtocolChanges} ) - gspec.Commit(db, trie.NewDatabase(db)) + gspec.Commit(db, trie.NewDatabase(db, nil)) hc, err := NewHeaderChain(db, gspec.Config, ethash.NewFaker(), func() bool { return false }) if err != nil { t.Fatal(err) diff --git a/core/mkalloc.go b/core/mkalloc.go index e4c2ec0d83..12c40c14fb 100644 --- a/core/mkalloc.go +++ b/core/mkalloc.go @@ -30,32 +30,55 @@ import ( "fmt" "math/big" "os" - "sort" "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{ Addr, Balance *big.Int } +type allocItem struct { + Addr *big.Int + Balance *big.Int + Misc *allocItemMisc `rlp:"optional"` +} -type allocList []allocItem +type allocItemMisc struct { + Nonce uint64 + Code []byte + Slots []allocItemStorageItem +} -func (a allocList) Len() int { return len(a) } -func (a allocList) Less(i, j int) bool { return a[i].Addr.Cmp(a[j].Addr) < 0 } -func (a allocList) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +type allocItemStorageItem struct { + Key common.Hash + Val common.Hash +} -func makelist(g *core.Genesis) allocList { - a := make(allocList, 0, len(g.Alloc)) +func makelist(g *core.Genesis) []allocItem { + items := make([]allocItem, 0, len(g.Alloc)) for addr, account := range g.Alloc { + var misc *allocItemMisc if len(account.Storage) > 0 || len(account.Code) > 0 || account.Nonce != 0 { - panic(fmt.Sprintf("can't encode account %x", addr)) + misc = &allocItemMisc{ + Nonce: account.Nonce, + Code: account.Code, + Slots: make([]allocItemStorageItem, 0, len(account.Storage)), + } + for key, val := range account.Storage { + misc.Slots = append(misc.Slots, allocItemStorageItem{key, val}) + } + slices.SortFunc(misc.Slots, func(a, b allocItemStorageItem) int { + return a.Key.Cmp(b.Key) + }) } bigAddr := new(big.Int).SetBytes(addr.Bytes()) - a = append(a, allocItem{bigAddr, account.Balance}) + items = append(items, allocItem{bigAddr, account.Balance, misc}) } - sort.Sort(a) - return a + slices.SortFunc(items, func(a, b allocItem) int { + return a.Addr.Cmp(b.Addr) + }) + return items } func makealloc(g *core.Genesis) string { diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index b479655b0b..97401d283c 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -22,15 +22,16 @@ import ( "errors" "fmt" "math/big" - "sort" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus/misc/eip4844" "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" "github.com/ethereum/go-ethereum/rlp" + "golang.org/x/exp/slices" ) // ReadCanonicalHash retrieves the hash assigned to a canonical block number. @@ -380,7 +381,7 @@ func ReadHeader(db ethdb.Reader, hash common.Hash, number uint64) *types.Header return nil } header := new(types.Header) - if err := rlp.Decode(bytes.NewReader(data), header); err != nil { + if err := rlp.DecodeBytes(data, header); err != nil { log.Error("Invalid block header RLP", "hash", hash, "err", err) return nil } @@ -497,7 +498,7 @@ func ReadBody(db ethdb.Reader, hash common.Hash, number uint64) *types.Body { return nil } body := new(types.Body) - if err := rlp.Decode(bytes.NewReader(data), body); err != nil { + if err := rlp.DecodeBytes(data, body); err != nil { log.Error("Invalid block body RLP", "hash", hash, "err", err) return nil } @@ -543,7 +544,7 @@ func ReadTd(db ethdb.Reader, hash common.Hash, number uint64) *big.Int { return nil } td := new(big.Int) - if err := rlp.Decode(bytes.NewReader(data), td); err != nil { + if err := rlp.DecodeBytes(data, td); err != nil { log.Error("Invalid block total difficulty RLP", "hash", hash, "err", err) return nil } @@ -637,13 +638,19 @@ func ReadReceipts(db ethdb.Reader, hash common.Hash, number uint64, time uint64, return nil } header := ReadHeader(db, hash, number) + var baseFee *big.Int if header == nil { baseFee = big.NewInt(0) } else { baseFee = header.BaseFee } - if err := receipts.DeriveFields(config, hash, number, time, baseFee, body.Transactions); err != nil { + // Compute effective blob gas price. + var blobGasPrice *big.Int + if header != nil && header.ExcessBlobGas != nil { + blobGasPrice = eip4844.CalcBlobFee(*header.ExcessBlobGas) + } + if err := receipts.DeriveFields(config, hash, number, time, baseFee, blobGasPrice, body.Transactions); err != nil { log.Error("Failed to derive block receipts fields", "hash", hash, "number", number, "err", err) return nil } @@ -724,7 +731,7 @@ func deriveLogFields(receipts []*receiptLogs, hash common.Hash, number uint64, t // 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. -func ReadLogs(db ethdb.Reader, hash common.Hash, number uint64, config *params.ChainConfig) [][]*types.Log { +func ReadLogs(db ethdb.Reader, hash common.Hash, number uint64) [][]*types.Log { // Retrieve the flattened receipt slice data := ReadReceiptsRLP(db, hash, number) if len(data) == 0 { @@ -836,23 +843,13 @@ type badBlock struct { Body *types.Body } -// badBlockList implements the sort interface to allow sorting a list of -// bad blocks by their number in the reverse order. -type badBlockList []*badBlock - -func (s badBlockList) Len() int { return len(s) } -func (s badBlockList) Less(i, j int) bool { - return s[i].Header.Number.Uint64() < s[j].Header.Number.Uint64() -} -func (s badBlockList) Swap(i, j int) { s[i], s[j] = s[j], s[i] } - // ReadBadBlock retrieves the bad block with the corresponding block hash. func ReadBadBlock(db ethdb.Reader, hash common.Hash) *types.Block { blob, err := db.Get(badBlockKey) if err != nil { return nil } - var badBlocks badBlockList + var badBlocks []*badBlock if err := rlp.DecodeBytes(blob, &badBlocks); err != nil { return nil } @@ -871,7 +868,7 @@ func ReadAllBadBlocks(db ethdb.Reader) []*types.Block { if err != nil { return nil } - var badBlocks badBlockList + var badBlocks []*badBlock if err := rlp.DecodeBytes(blob, &badBlocks); err != nil { return nil } @@ -889,7 +886,7 @@ func WriteBadBlock(db ethdb.KeyValueStore, block *types.Block) { if err != nil { log.Warn("Failed to load old bad blocks", "error", err) } - var badBlocks badBlockList + var badBlocks []*badBlock if len(blob) > 0 { if err := rlp.DecodeBytes(blob, &badBlocks); err != nil { log.Crit("Failed to decode old bad blocks", "error", err) @@ -905,7 +902,10 @@ func WriteBadBlock(db ethdb.KeyValueStore, block *types.Block) { Header: block.Header(), Body: block.Body(), }) - sort.Sort(sort.Reverse(badBlocks)) + slices.SortFunc(badBlocks, func(a, b *badBlock) int { + // Note: sorting in descending number order. + return -a.Header.Number.Cmp(b.Header.Number) + }) if len(badBlocks) > badBlockToKeep { badBlocks = badBlocks[:badBlockToKeep] } diff --git a/core/rawdb/accessors_chain_test.go b/core/rawdb/accessors_chain_test.go index 32e38a81ce..a7ceb72998 100644 --- a/core/rawdb/accessors_chain_test.go +++ b/core/rawdb/accessors_chain_test.go @@ -85,7 +85,7 @@ func TestBodyStorage(t *testing.T) { WriteBody(db, hash, 0, body) if entry := ReadBody(db, hash, 0); entry == nil { t.Fatalf("Stored body not found") - } else if types.DeriveSha(types.Transactions(entry.Transactions), newHasher()) != types.DeriveSha(types.Transactions(body.Transactions), newHasher()) || types.CalcUncleHash(entry.Uncles) != types.CalcUncleHash(body.Uncles) { + } else if types.DeriveSha(types.Transactions(entry.Transactions), newTestHasher()) != types.DeriveSha(types.Transactions(body.Transactions), newTestHasher()) || types.CalcUncleHash(entry.Uncles) != types.CalcUncleHash(body.Uncles) { t.Fatalf("Retrieved body mismatch: have %v, want %v", entry, body) } if entry := ReadBodyRLP(db, hash, 0); entry == nil { @@ -139,7 +139,7 @@ func TestBlockStorage(t *testing.T) { } if entry := ReadBody(db, block.Hash(), block.NumberU64()); entry == nil { t.Fatalf("Stored body not found") - } else if types.DeriveSha(types.Transactions(entry.Transactions), newHasher()) != types.DeriveSha(block.Transactions(), newHasher()) || types.CalcUncleHash(entry.Uncles) != types.CalcUncleHash(block.Uncles()) { + } else if types.DeriveSha(types.Transactions(entry.Transactions), newTestHasher()) != types.DeriveSha(block.Transactions(), newTestHasher()) || types.CalcUncleHash(entry.Uncles) != types.CalcUncleHash(block.Uncles()) { t.Fatalf("Retrieved body mismatch: have %v, want %v", entry, block.Body()) } // Delete the block and verify the execution @@ -435,12 +435,12 @@ func checkReceiptsRLP(have, want types.Receipts) error { func TestAncientStorage(t *testing.T) { // Freezer style fast import the chain. frdir := t.TempDir() - db, err := NewDatabaseWithFreezer(NewMemoryDatabase(), frdir, "", false) if err != nil { t.Fatalf("failed to create database with ancient backend") } defer db.Close() + // Create a test block block := types.NewBlockWithHeader(&types.Header{ Number: big.NewInt(0), @@ -736,7 +736,7 @@ func TestReadLogs(t *testing.T) { // Insert the receipt slice into the database and check presence WriteReceipts(db, hash, 0, receipts) - logs := ReadLogs(db, hash, 0, params.TestChainConfig) + logs := ReadLogs(db, hash, 0) if len(logs) == 0 { t.Fatalf("no logs returned") } diff --git a/core/rawdb/accessors_indexes_test.go b/core/rawdb/accessors_indexes_test.go index c5447b16d2..124389ba7a 100644 --- a/core/rawdb/accessors_indexes_test.go +++ b/core/rawdb/accessors_indexes_test.go @@ -18,42 +18,18 @@ package rawdb import ( "bytes" - "hash" "math/big" "testing" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/internal/blocktest" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" - "golang.org/x/crypto/sha3" ) -// testHasher is the helper tool for transaction/receipt list hashing. -// The original hasher is trie, in order to get rid of import cycle, -// use the testing hasher instead. -type testHasher struct { - hasher hash.Hash -} - -func newHasher() *testHasher { - return &testHasher{hasher: sha3.NewLegacyKeccak256()} -} - -func (h *testHasher) Reset() { - h.hasher.Reset() -} - -func (h *testHasher) Update(key, val []byte) error { - h.hasher.Write(key) - h.hasher.Write(val) - return nil -} - -func (h *testHasher) Hash() common.Hash { - return common.BytesToHash(h.hasher.Sum(nil)) -} +var newTestHasher = blocktest.NewHasher // Tests that positional lookup metadata can be stored and retrieved. func TestLookupStorage(t *testing.T) { @@ -100,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, newHasher()) + block := types.NewBlock(&types.Header{Number: big.NewInt(314)}, txs, nil, nil, newTestHasher()) // Check that no transactions entries are in a pristine database for i, tx := range txs { @@ -142,7 +118,7 @@ func TestDeleteBloomBits(t *testing.T) { for i := uint(0); i < 2; i++ { for s := uint64(0); s < 2; s++ { WriteBloomBits(db, i, s, params.MainnetGenesisHash, []byte{0x01, 0x02}) - WriteBloomBits(db, i, s, params.RinkebyGenesisHash, []byte{0x01, 0x02}) + WriteBloomBits(db, i, s, params.SepoliaGenesisHash, []byte{0x01, 0x02}) } } check := func(bit uint, section uint64, head common.Hash, exist bool) { @@ -156,25 +132,25 @@ func TestDeleteBloomBits(t *testing.T) { } // Check the existence of written data. check(0, 0, params.MainnetGenesisHash, true) - check(0, 0, params.RinkebyGenesisHash, true) + check(0, 0, params.SepoliaGenesisHash, true) // Check the existence of deleted data. DeleteBloombits(db, 0, 0, 1) check(0, 0, params.MainnetGenesisHash, false) - check(0, 0, params.RinkebyGenesisHash, false) + check(0, 0, params.SepoliaGenesisHash, false) check(0, 1, params.MainnetGenesisHash, true) - check(0, 1, params.RinkebyGenesisHash, true) + check(0, 1, params.SepoliaGenesisHash, true) // Check the existence of deleted data. DeleteBloombits(db, 0, 0, 2) check(0, 0, params.MainnetGenesisHash, false) - check(0, 0, params.RinkebyGenesisHash, false) + check(0, 0, params.SepoliaGenesisHash, false) check(0, 1, params.MainnetGenesisHash, false) - check(0, 1, params.RinkebyGenesisHash, false) + check(0, 1, params.SepoliaGenesisHash, false) // Bit1 shouldn't be affect. check(1, 0, params.MainnetGenesisHash, true) - check(1, 0, params.RinkebyGenesisHash, true) + check(1, 0, params.SepoliaGenesisHash, true) check(1, 1, params.MainnetGenesisHash, true) - check(1, 1, params.RinkebyGenesisHash, true) + check(1, 1, params.SepoliaGenesisHash, true) } diff --git a/core/rawdb/accessors_metadata.go b/core/rawdb/accessors_metadata.go index 2ff29d1add..859566f722 100644 --- a/core/rawdb/accessors_metadata.go +++ b/core/rawdb/accessors_metadata.go @@ -111,10 +111,10 @@ const crashesToKeep = 10 func PushUncleanShutdownMarker(db ethdb.KeyValueStore) ([]uint64, uint64, error) { var uncleanShutdowns crashList // Read old data - if data, err := db.Get(uncleanShutdownKey); err != nil { - log.Warn("Error reading unclean shutdown markers", "error", err) - } else if err := rlp.DecodeBytes(data, &uncleanShutdowns); err != nil { - return nil, 0, err + if data, err := db.Get(uncleanShutdownKey); err == nil { + if err := rlp.DecodeBytes(data, &uncleanShutdowns); err != nil { + return nil, 0, err + } } var discarded = uncleanShutdowns.Discarded var previous = make([]uint64, len(uncleanShutdowns.Recent)) diff --git a/core/rawdb/accessors_state.go b/core/rawdb/accessors_state.go index 39900df23e..9ce58e7d27 100644 --- a/core/rawdb/accessors_state.go +++ b/core/rawdb/accessors_state.go @@ -17,6 +17,8 @@ package rawdb import ( + "encoding/binary" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" @@ -92,3 +94,173 @@ func DeleteCode(db ethdb.KeyValueWriter, hash common.Hash) { log.Crit("Failed to delete contract code", "err", err) } } + +// ReadStateID retrieves the state id with the provided state root. +func ReadStateID(db ethdb.KeyValueReader, root common.Hash) *uint64 { + data, err := db.Get(stateIDKey(root)) + if err != nil || len(data) == 0 { + return nil + } + number := binary.BigEndian.Uint64(data) + return &number +} + +// WriteStateID writes the provided state lookup to database. +func WriteStateID(db ethdb.KeyValueWriter, root common.Hash, id uint64) { + var buff [8]byte + binary.BigEndian.PutUint64(buff[:], id) + if err := db.Put(stateIDKey(root), buff[:]); err != nil { + log.Crit("Failed to store state ID", "err", err) + } +} + +// DeleteStateID deletes the specified state lookup from the database. +func DeleteStateID(db ethdb.KeyValueWriter, root common.Hash) { + if err := db.Delete(stateIDKey(root)); err != nil { + log.Crit("Failed to delete state ID", "err", err) + } +} + +// ReadPersistentStateID retrieves the id of the persistent state from the database. +func ReadPersistentStateID(db ethdb.KeyValueReader) uint64 { + data, _ := db.Get(persistentStateIDKey) + if len(data) != 8 { + return 0 + } + return binary.BigEndian.Uint64(data) +} + +// WritePersistentStateID stores the id of the persistent state into database. +func WritePersistentStateID(db ethdb.KeyValueWriter, number uint64) { + if err := db.Put(persistentStateIDKey, encodeBlockNumber(number)); err != nil { + log.Crit("Failed to store the persistent state ID", "err", err) + } +} + +// ReadTrieJournal retrieves the serialized in-memory trie nodes of layers saved at +// the last shutdown. +func ReadTrieJournal(db ethdb.KeyValueReader) []byte { + data, _ := db.Get(trieJournalKey) + return data +} + +// WriteTrieJournal stores the serialized in-memory trie nodes of layers to save at +// shutdown. +func WriteTrieJournal(db ethdb.KeyValueWriter, journal []byte) { + if err := db.Put(trieJournalKey, journal); err != nil { + log.Crit("Failed to store tries journal", "err", err) + } +} + +// DeleteTrieJournal deletes the serialized in-memory trie nodes of layers saved at +// the last shutdown. +func DeleteTrieJournal(db ethdb.KeyValueWriter) { + if err := db.Delete(trieJournalKey); err != nil { + log.Crit("Failed to remove tries journal", "err", err) + } +} + +// ReadStateHistoryMeta retrieves the metadata corresponding to the specified +// state history. Compute the position of state history in freezer by minus +// one since the id of first state history starts from one(zero for initial +// state). +func ReadStateHistoryMeta(db ethdb.AncientReaderOp, id uint64) []byte { + blob, err := db.Ancient(stateHistoryMeta, id-1) + if err != nil { + return nil + } + return blob +} + +// ReadStateHistoryMetaList retrieves a batch of meta objects with the specified +// start position and count. Compute the position of state history in freezer by +// minus one since the id of first state history starts from one(zero for initial +// state). +func ReadStateHistoryMetaList(db ethdb.AncientReaderOp, start uint64, count uint64) ([][]byte, error) { + return db.AncientRange(stateHistoryMeta, start-1, count, 0) +} + +// ReadStateAccountIndex retrieves the state root corresponding to the specified +// state history. Compute the position of state history in freezer by minus one +// since the id of first state history starts from one(zero for initial state). +func ReadStateAccountIndex(db ethdb.AncientReaderOp, id uint64) []byte { + blob, err := db.Ancient(stateHistoryAccountIndex, id-1) + if err != nil { + return nil + } + return blob +} + +// ReadStateStorageIndex retrieves the state root corresponding to the specified +// state history. Compute the position of state history in freezer by minus one +// since the id of first state history starts from one(zero for initial state). +func ReadStateStorageIndex(db ethdb.AncientReaderOp, id uint64) []byte { + blob, err := db.Ancient(stateHistoryStorageIndex, id-1) + if err != nil { + return nil + } + return blob +} + +// ReadStateAccountHistory retrieves the state root corresponding to the specified +// state history. Compute the position of state history in freezer by minus one +// since the id of first state history starts from one(zero for initial state). +func ReadStateAccountHistory(db ethdb.AncientReaderOp, id uint64) []byte { + blob, err := db.Ancient(stateHistoryAccountData, id-1) + if err != nil { + return nil + } + return blob +} + +// ReadStateStorageHistory retrieves the state root corresponding to the specified +// state history. Compute the position of state history in freezer by minus one +// since the id of first state history starts from one(zero for initial state). +func ReadStateStorageHistory(db ethdb.AncientReaderOp, id uint64) []byte { + blob, err := db.Ancient(stateHistoryStorageData, id-1) + if err != nil { + return nil + } + return blob +} + +// ReadStateHistory retrieves the state history from database with provided id. +// Compute the position of state history in freezer by minus one since the id +// of first state history starts from one(zero for initial state). +func ReadStateHistory(db ethdb.AncientReaderOp, id uint64) ([]byte, []byte, []byte, []byte, []byte, error) { + meta, err := db.Ancient(stateHistoryMeta, id-1) + if err != nil { + return nil, nil, nil, nil, nil, err + } + accountIndex, err := db.Ancient(stateHistoryAccountIndex, id-1) + if err != nil { + return nil, nil, nil, nil, nil, err + } + storageIndex, err := db.Ancient(stateHistoryStorageIndex, id-1) + if err != nil { + return nil, nil, nil, nil, nil, err + } + accountData, err := db.Ancient(stateHistoryAccountData, id-1) + if err != nil { + return nil, nil, nil, nil, nil, err + } + storageData, err := db.Ancient(stateHistoryStorageData, id-1) + if err != nil { + return nil, nil, nil, nil, nil, err + } + return meta, accountIndex, storageIndex, accountData, storageData, nil +} + +// WriteStateHistory writes the provided state history to database. Compute the +// position of state history in freezer by minus one since the id of first state +// history starts from one(zero for initial state). +func WriteStateHistory(db ethdb.AncientWriter, id uint64, meta []byte, accountIndex []byte, storageIndex []byte, accounts []byte, storages []byte) { + db.ModifyAncients(func(op ethdb.AncientWriteOp) error { + op.AppendRaw(stateHistoryMeta, id-1, meta) + op.AppendRaw(stateHistoryAccountIndex, id-1, accountIndex) + op.AppendRaw(stateHistoryStorageIndex, id-1, storageIndex) + op.AppendRaw(stateHistoryAccountData, id-1, accounts) + op.AppendRaw(stateHistoryStorageData, id-1, storages) + return nil + }) +} diff --git a/core/rawdb/accessors_sync.go b/core/rawdb/accessors_sync.go index e87ad43c36..7a7374e168 100644 --- a/core/rawdb/accessors_sync.go +++ b/core/rawdb/accessors_sync.go @@ -17,8 +17,6 @@ package rawdb import ( - "bytes" - "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" @@ -53,7 +51,7 @@ func ReadSkeletonHeader(db ethdb.KeyValueReader, number uint64) *types.Header { return nil } header := new(types.Header) - if err := rlp.Decode(bytes.NewReader(data), header); err != nil { + if err := rlp.DecodeBytes(data, header); err != nil { log.Error("Invalid skeleton header RLP", "number", number, "err", err) return nil } diff --git a/core/rawdb/accessors_trie.go b/core/rawdb/accessors_trie.go index e240213025..f5c2f8899a 100644 --- a/core/rawdb/accessors_trie.go +++ b/core/rawdb/accessors_trie.go @@ -36,7 +36,7 @@ import ( // // Now this scheme is still kept for backward compatibility, and it will be used // for archive node and some other tries(e.g. light trie). -const HashScheme = "hashScheme" +const HashScheme = "hash" // PathScheme is the new path-based state scheme with which trie nodes are stored // in the disk with node path as the database key. This scheme will only store one @@ -44,23 +44,25 @@ const HashScheme = "hashScheme" // is native. At the same time, this scheme will put adjacent trie nodes in the same // area of the disk with good data locality property. But this scheme needs to rely // on extra state diffs to survive deep reorg. -const PathScheme = "pathScheme" +const PathScheme = "path" -// nodeHasher used to derive the hash of trie node. -type nodeHasher struct{ sha crypto.KeccakState } +// 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 &nodeHasher{sha: sha3.NewLegacyKeccak256().(crypto.KeccakState)} }, + New: func() interface{} { return &hasher{sha: sha3.NewLegacyKeccak256().(crypto.KeccakState)} }, } -func newNodeHasher() *nodeHasher { return hasherPool.Get().(*nodeHasher) } -func returnHasherToPool(h *nodeHasher) { hasherPool.Put(h) } +func newHasher() *hasher { + return hasherPool.Get().(*hasher) +} -func (h *nodeHasher) hashData(data []byte) (n common.Hash) { - h.sha.Reset() - h.sha.Write(data) - h.sha.Read(n[:]) - return n +func (h *hasher) hash(data []byte) common.Hash { + return crypto.HashData(h.sha, data) +} + +func (h *hasher) release() { + hasherPool.Put(h) } // ReadAccountTrieNode retrieves the account trie node and the associated node @@ -70,9 +72,9 @@ func ReadAccountTrieNode(db ethdb.KeyValueReader, path []byte) ([]byte, common.H if err != nil { return nil, common.Hash{} } - hasher := newNodeHasher() - defer returnHasherToPool(hasher) - return data, hasher.hashData(data) + h := newHasher() + defer h.release() + return data, h.hash(data) } // HasAccountTrieNode checks the account trie node presence with the specified @@ -82,9 +84,9 @@ func HasAccountTrieNode(db ethdb.KeyValueReader, path []byte, hash common.Hash) if err != nil { return false } - hasher := newNodeHasher() - defer returnHasherToPool(hasher) - return hasher.hashData(data) == hash + h := newHasher() + defer h.release() + return h.hash(data) == hash } // WriteAccountTrieNode writes the provided account trie node into database. @@ -108,9 +110,9 @@ func ReadStorageTrieNode(db ethdb.KeyValueReader, accountHash common.Hash, path if err != nil { return nil, common.Hash{} } - hasher := newNodeHasher() - defer returnHasherToPool(hasher) - return data, hasher.hashData(data) + h := newHasher() + defer h.release() + return data, h.hash(data) } // HasStorageTrieNode checks the storage trie node presence with the provided @@ -120,9 +122,9 @@ func HasStorageTrieNode(db ethdb.KeyValueReader, accountHash common.Hash, path [ if err != nil { return false } - hasher := newNodeHasher() - defer returnHasherToPool(hasher) - return hasher.hashData(data) == hash + h := newHasher() + defer h.release() + return h.hash(data) == hash } // WriteStorageTrieNode writes the provided storage trie node into database. @@ -261,3 +263,25 @@ func DeleteTrieNode(db ethdb.KeyValueWriter, owner common.Hash, path []byte, has panic(fmt.Sprintf("Unknown scheme %v", scheme)) } } + +// 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 { + 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. + header := ReadHeader(db, ReadCanonicalHash(db, 0), 0) + if header == nil { + return "" // empty datadir + } + blob = ReadLegacyTrieNode(db, header.Root) + if len(blob) == 0 { + return "" // no state in disk + } + return HashScheme +} diff --git a/core/rawdb/ancient_scheme.go b/core/rawdb/ancient_scheme.go index b0428c5f5b..6f409fff1d 100644 --- a/core/rawdb/ancient_scheme.go +++ b/core/rawdb/ancient_scheme.go @@ -16,6 +16,8 @@ package rawdb +import "path/filepath" + // The list of table names of chain freezer. const ( // ChainFreezerHeaderTable indicates the name of the freezer header table. @@ -44,10 +46,36 @@ var chainFreezerNoSnappy = map[string]bool{ ChainFreezerDifficultyTable: true, } +const ( + // stateHistoryTableSize defines the maximum size of freezer data files. + stateHistoryTableSize = 2 * 1000 * 1000 * 1000 + + // stateHistoryAccountIndex indicates the name of the freezer state history table. + stateHistoryMeta = "history.meta" + stateHistoryAccountIndex = "account.index" + stateHistoryStorageIndex = "storage.index" + stateHistoryAccountData = "account.data" + stateHistoryStorageData = "storage.data" +) + +var stateFreezerNoSnappy = map[string]bool{ + stateHistoryMeta: true, + stateHistoryAccountIndex: false, + stateHistoryStorageIndex: false, + stateHistoryAccountData: false, + stateHistoryStorageData: false, +} + // 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. ) // freezers the collections of all builtin freezers. -var freezers = []string{chainFreezerName} +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) +} diff --git a/core/rawdb/ancient_utils.go b/core/rawdb/ancient_utils.go index 363a911aee..96bd9ee408 100644 --- a/core/rawdb/ancient_utils.go +++ b/core/rawdb/ancient_utils.go @@ -50,36 +50,58 @@ func (info *freezerInfo) size() common.StorageSize { return total } +func inspect(name string, order map[string]bool, reader ethdb.AncientReader) (freezerInfo, error) { + info := freezerInfo{name: name} + for t := range order { + size, err := reader.AncientSize(t) + if err != nil { + return freezerInfo{}, err + } + info.sizes = append(info.sizes, tableSize{name: t, size: common.StorageSize(size)}) + } + // Retrieve the number of last stored item + ancients, err := reader.Ancients() + if err != nil { + return freezerInfo{}, err + } + info.head = ancients - 1 + + // Retrieve the number of first stored item + tail, err := reader.Tail() + if err != nil { + return freezerInfo{}, err + } + info.tail = tail + return info, nil +} + // inspectFreezers inspects all freezers registered in the system. func inspectFreezers(db ethdb.Database) ([]freezerInfo, error) { var infos []freezerInfo for _, freezer := range freezers { switch freezer { case chainFreezerName: - // Chain ancient store is a bit special. It's always opened along - // with the key-value store, inspect the chain store directly. - info := freezerInfo{name: freezer} - // Retrieve storage size of every contained table. - for table := range chainFreezerNoSnappy { - size, err := db.AncientSize(table) - if err != nil { - return nil, err - } - info.sizes = append(info.sizes, tableSize{name: table, size: common.StorageSize(size)}) - } - // Retrieve the number of last stored item - ancients, err := db.Ancients() + info, err := inspect(chainFreezerName, chainFreezerNoSnappy, db) if err != nil { return nil, err } - info.head = ancients - 1 + infos = append(infos, info) - // Retrieve the number of first stored item - tail, err := db.Tail() + case stateFreezerName: + datadir, err := db.AncientDatadir() + if err != nil { + return nil, err + } + f, err := NewStateFreezer(datadir, true) + if err != nil { + return nil, err + } + defer f.Close() + + info, err := inspect(stateFreezerName, stateFreezerNoSnappy, f) if err != nil { return nil, err } - info.tail = tail infos = append(infos, info) default: diff --git a/core/rawdb/chain_iterator_test.go b/core/rawdb/chain_iterator_test.go index e1f5159753..9580cd92a8 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, newHasher()) // Empty genesis block + block = types.NewBlock(&types.Header{Number: big.NewInt(int64(0))}, nil, 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, newHasher()) + block = types.NewBlock(&types.Header{Number: big.NewInt(int64(i))}, []*types.Transaction{tx}, nil, 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, newHasher()) + block = types.NewBlock(&types.Header{Number: big.NewInt(int64(0))}, nil, 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, newHasher()) + block = types.NewBlock(&types.Header{Number: big.NewInt(int64(i))}, []*types.Transaction{tx}, nil, nil, newTestHasher()) WriteBlock(chainDb, block) WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64()) } diff --git a/core/rawdb/database.go b/core/rawdb/database.go index e864bcb2e8..7a78456382 100644 --- a/core/rawdb/database.go +++ b/core/rawdb/database.go @@ -123,13 +123,13 @@ func (db *nofreezedb) ModifyAncients(func(ethdb.AncientWriteOp) error) (int64, e } // TruncateHead returns an error as we don't have a backing chain freezer. -func (db *nofreezedb) TruncateHead(items uint64) error { - return errNotSupported +func (db *nofreezedb) TruncateHead(items uint64) (uint64, error) { + return 0, errNotSupported } // TruncateTail returns an error as we don't have a backing chain freezer. -func (db *nofreezedb) TruncateTail(items uint64) error { - return errNotSupported +func (db *nofreezedb) TruncateTail(items uint64) (uint64, error) { + return 0, errNotSupported } // Sync returns an error as we don't have a backing chain freezer. @@ -326,10 +326,10 @@ const ( dbLeveldb = "leveldb" ) -// hasPreexistingDb checks the given data directory whether a database is already +// PreexistingDatabase checks the given data directory whether a database is already // instantiated at that location, and if so, returns the type of database (or the // empty string). -func hasPreexistingDb(path string) string { +func PreexistingDatabase(path string) string { if _, err := os.Stat(filepath.Join(path, "CURRENT")); err != nil { return "" // No pre-existing db } @@ -352,6 +352,9 @@ type OpenOptions struct { Cache int // the capacity(in megabytes) of the data caching Handles int // number of files to be open simultaneously ReadOnly bool + // Ephemeral means that filesystem sync operations should be avoided: data integrity in the face of + // a crash is not important. This option should typically be used in tests. + Ephemeral bool } // openKeyValueDatabase opens a disk-based key-value database, e.g. leveldb or pebble. @@ -367,14 +370,14 @@ func openKeyValueDatabase(o OpenOptions) (ethdb.Database, error) { } // Retrieve any pre-existing database's type and use that or the requested one // as long as there's no conflict between the two types - existingDb := hasPreexistingDb(o.Directory) + existingDb := PreexistingDatabase(o.Directory) if len(existingDb) != 0 && len(o.Type) != 0 && o.Type != existingDb { return nil, fmt.Errorf("db.engine choice was %v but found pre-existing %v database in specified data directory", o.Type, existingDb) } if o.Type == dbPebble || existingDb == dbPebble { if PebbleEnabled { log.Info("Using pebble as the backing database") - return NewPebbleDBDatabase(o.Directory, o.Cache, o.Handles, o.Namespace, o.ReadOnly) + return NewPebbleDBDatabase(o.Directory, o.Cache, o.Handles, o.Namespace, o.ReadOnly, o.Ephemeral) } else { return nil, errors.New("db.engine 'pebble' not supported on this platform") } @@ -387,7 +390,7 @@ func openKeyValueDatabase(o OpenOptions) (ethdb.Database, error) { // on supported platforms and LevelDB on anything else. if PebbleEnabled { log.Info("Defaulting to pebble as the backing database") - return NewPebbleDBDatabase(o.Directory, o.Cache, o.Handles, o.Namespace, o.ReadOnly) + return NewPebbleDBDatabase(o.Directory, o.Cache, o.Handles, o.Namespace, o.ReadOnly, o.Ephemeral) } else { log.Info("Defaulting to leveldb as the backing database") return NewLevelDBDatabase(o.Directory, o.Cache, o.Handles, o.Namespace, o.ReadOnly) @@ -463,7 +466,10 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { tds stat numHashPairings stat hashNumPairings stat - tries stat + legacyTries stat + stateLookups stat + accountTries stat + storageTries stat codes stat txLookups stat accountSnaps stat @@ -504,8 +510,14 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { numHashPairings.Add(size) case bytes.HasPrefix(key, headerNumberPrefix) && len(key) == (len(headerNumberPrefix)+common.HashLength): hashNumPairings.Add(size) - case len(key) == common.HashLength: - tries.Add(size) + case IsLegacyTrieNode(key, it.Value()): + legacyTries.Add(size) + case bytes.HasPrefix(key, stateIDPrefix) && len(key) == len(stateIDPrefix)+common.HashLength: + stateLookups.Add(size) + case IsAccountTrieNode(key): + accountTries.Add(size) + case IsStorageTrieNode(key): + storageTries.Add(size) case bytes.HasPrefix(key, CodePrefix) && len(key) == len(CodePrefix)+common.HashLength: codes.Add(size) case bytes.HasPrefix(key, txLookupPrefix) && len(key) == (len(txLookupPrefix)+common.HashLength): @@ -543,6 +555,7 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { lastPivotKey, fastTrieProgressKey, snapshotDisabledKey, SnapshotRootKey, snapshotJournalKey, snapshotGeneratorKey, snapshotRecoveryKey, txIndexTailKey, fastTxLookupLimitKey, uncleanShutdownKey, badBlockKey, transitionStatusKey, skeletonSyncStatusKey, + persistentStateIDKey, trieJournalKey, snapshotSyncStatusKey, } { if bytes.Equal(key, meta) { metadata.Add(size) @@ -571,7 +584,10 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { {"Key-Value store", "Transaction index", txLookups.Size(), txLookups.Count()}, {"Key-Value store", "Bloombit index", bloomBits.Size(), bloomBits.Count()}, {"Key-Value store", "Contract codes", codes.Size(), codes.Count()}, - {"Key-Value store", "Trie nodes", tries.Size(), tries.Count()}, + {"Key-Value store", "Hash trie nodes", legacyTries.Size(), legacyTries.Count()}, + {"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", "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/databases_64bit.go b/core/rawdb/databases_64bit.go index 73bfeb2083..1593e89bfe 100644 --- a/core/rawdb/databases_64bit.go +++ b/core/rawdb/databases_64bit.go @@ -28,8 +28,8 @@ const PebbleEnabled = true // NewPebbleDBDatabase creates a persistent key-value database without a freezer // moving immutable chain segments into cold storage. -func NewPebbleDBDatabase(file string, cache int, handles int, namespace string, readonly bool) (ethdb.Database, error) { - db, err := pebble.New(file, cache, handles, namespace, readonly) +func NewPebbleDBDatabase(file string, cache int, handles int, namespace string, readonly, ephemeral bool) (ethdb.Database, error) { + db, err := pebble.New(file, cache, handles, namespace, readonly, ephemeral) if err != nil { return nil, err } diff --git a/core/rawdb/databases_non64bit.go b/core/rawdb/databases_non64bit.go index 1f10c2f52b..fb0777a5e6 100644 --- a/core/rawdb/databases_non64bit.go +++ b/core/rawdb/databases_non64bit.go @@ -29,6 +29,6 @@ const PebbleEnabled = false // NewPebbleDBDatabase creates a persistent key-value database without a freezer // moving immutable chain segments into cold storage. -func NewPebbleDBDatabase(file string, cache int, handles int, namespace string, readonly bool) (ethdb.Database, error) { +func NewPebbleDBDatabase(file string, cache int, handles int, namespace string, readonly, ephemeral bool) (ethdb.Database, error) { return nil, errors.New("pebble is not supported on this platform") } diff --git a/core/rawdb/freezer.go b/core/rawdb/freezer.go index 323dc1ddb3..a9fe234321 100644 --- a/core/rawdb/freezer.go +++ b/core/rawdb/freezer.go @@ -197,9 +197,10 @@ func (f *Freezer) Ancient(kind string, number uint64) ([]byte, error) { // AncientRange retrieves multiple items in sequence, starting from the index 'start'. // It will return -// - at most 'max' items, -// - at least 1 item (even if exceeding the maxByteSize), but will otherwise -// return as many items as fit into maxByteSize. +// - 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 *Freezer) AncientRange(kind string, start, count, maxBytes uint64) ([][]byte, error) { if table := f.tables[kind]; table != nil { return table.RetrieveItems(start, count, maxBytes) @@ -274,43 +275,46 @@ func (f *Freezer) ModifyAncients(fn func(ethdb.AncientWriteOp) error) (writeSize } // TruncateHead discards any recent data above the provided threshold number. -func (f *Freezer) TruncateHead(items uint64) error { +// It returns the previous head number. +func (f *Freezer) TruncateHead(items uint64) (uint64, error) { if f.readonly { - return errReadOnly + return 0, errReadOnly } f.writeLock.Lock() defer f.writeLock.Unlock() - if f.frozen.Load() <= items { - return nil + oitems := f.frozen.Load() + if oitems <= items { + return oitems, nil } for _, table := range f.tables { if err := table.truncateHead(items); err != nil { - return err + return 0, err } } f.frozen.Store(items) - return nil + return oitems, nil } // TruncateTail discards any recent data below the provided threshold number. -func (f *Freezer) TruncateTail(tail uint64) error { +func (f *Freezer) TruncateTail(tail uint64) (uint64, error) { if f.readonly { - return errReadOnly + return 0, errReadOnly } f.writeLock.Lock() defer f.writeLock.Unlock() - if f.tail.Load() >= tail { - return nil + old := f.tail.Load() + if old >= tail { + return old, nil } for _, table := range f.tables { if err := table.truncateTail(tail); err != nil { - return err + return 0, err } } f.tail.Store(tail) - return nil + return old, nil } // Sync flushes all data tables to disk. @@ -434,7 +438,7 @@ func (f *Freezer) MigrateTable(kind string, convert convertLegacyFn) error { // 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 fmt.Errorf("migration not supported for tail-deleted freezers") + 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 diff --git a/core/rawdb/freezer_resettable.go b/core/rawdb/freezer_resettable.go index f9a56c6de5..0a3892bcdf 100644 --- a/core/rawdb/freezer_resettable.go +++ b/core/rawdb/freezer_resettable.go @@ -170,7 +170,8 @@ func (f *ResettableFreezer) ModifyAncients(fn func(ethdb.AncientWriteOp) error) } // TruncateHead discards any recent data above the provided threshold number. -func (f *ResettableFreezer) TruncateHead(items uint64) error { +// It returns the previous head number. +func (f *ResettableFreezer) TruncateHead(items uint64) (uint64, error) { f.lock.RLock() defer f.lock.RUnlock() @@ -178,7 +179,8 @@ func (f *ResettableFreezer) TruncateHead(items uint64) error { } // TruncateTail discards any recent data below the provided threshold number. -func (f *ResettableFreezer) TruncateTail(tail uint64) error { +// It returns the previous value +func (f *ResettableFreezer) TruncateTail(tail uint64) (uint64, error) { f.lock.RLock() defer f.lock.RUnlock() diff --git a/core/rawdb/freezer_table.go b/core/rawdb/freezer_table.go index 928b37d70b..fc6316c953 100644 --- a/core/rawdb/freezer_table.go +++ b/core/rawdb/freezer_table.go @@ -712,7 +712,7 @@ func (t *freezerTable) RetrieveItems(start, count, maxBytes uint64) ([][]byte, e if !t.noCompression { decompressedSize, _ = snappy.DecodedLen(item) } - if i > 0 && uint64(outputSize+decompressedSize) > maxBytes { + if i > 0 && maxBytes != 0 && uint64(outputSize+decompressedSize) > maxBytes { break } if !t.noCompression { @@ -730,8 +730,10 @@ func (t *freezerTable) RetrieveItems(start, count, maxBytes uint64) ([][]byte, e } // retrieveItems reads up to 'count' items from the table. It reads at least -// one item, but otherwise avoids reading more than maxBytes bytes. -// It returns the (potentially compressed) data, and the sizes. +// one item, but otherwise avoids reading more than maxBytes bytes. Freezer +// will ignore the size limitation and continuously allocate memory to store +// data if maxBytes is 0. It returns the (potentially compressed) data, and +// the sizes. func (t *freezerTable) retrieveItems(start, count, maxBytes uint64) ([]byte, []int, error) { t.lock.RLock() defer t.lock.RUnlock() @@ -752,25 +754,22 @@ func (t *freezerTable) retrieveItems(start, count, maxBytes uint64) ([]byte, []i if start+count > items { count = items - start } - var ( - output = make([]byte, maxBytes) // Buffer to read data into - outputSize int // Used size of that buffer - ) + var output []byte // Buffer to read data into + if maxBytes != 0 { + output = make([]byte, 0, maxBytes) + } else { + output = make([]byte, 0, 1024) // initial buffer cap + } // readData is a helper method to read a single data item from disk. readData := func(fileId, start uint32, length int) error { - // In case a small limit is used, and the elements are large, may need to - // realloc the read-buffer when reading the first (and only) item. - if len(output) < length { - output = make([]byte, length) - } + output = grow(output, length) dataFile, exist := t.files[fileId] if !exist { return fmt.Errorf("missing data file %d", fileId) } - if _, err := dataFile.ReadAt(output[outputSize:outputSize+length], int64(start)); err != nil { + if _, err := dataFile.ReadAt(output[len(output)-length:], int64(start)); err != nil { return err } - outputSize += length return nil } // Read all the indexes in one go @@ -801,7 +800,7 @@ func (t *freezerTable) retrieveItems(start, count, maxBytes uint64) ([]byte, []i } readStart = 0 } - if i > 0 && uint64(totalSize+size) > maxBytes { + if i > 0 && uint64(totalSize+size) > maxBytes && maxBytes != 0 { // About to break out due to byte limit being exceeded. We don't // read this last item, but we need to do the deferred reads now. if unreadSize > 0 { @@ -815,7 +814,7 @@ func (t *freezerTable) retrieveItems(start, count, maxBytes uint64) ([]byte, []i unreadSize += size totalSize += size sizes = append(sizes, size) - if i == len(indices)-2 || uint64(totalSize) > maxBytes { + if i == len(indices)-2 || (uint64(totalSize) > maxBytes && maxBytes != 0) { // Last item, need to do the read now if err := readData(secondIndex.filenum, readStart, unreadSize); err != nil { return nil, nil, err @@ -826,7 +825,7 @@ func (t *freezerTable) retrieveItems(start, count, maxBytes uint64) ([]byte, []i // Update metrics. t.readMeter.Mark(int64(totalSize)) - return output[:outputSize], sizes, nil + return output, sizes, nil } // has returns an indicator whether the specified number data is still accessible diff --git a/core/rawdb/freezer_table_test.go b/core/rawdb/freezer_table_test.go index 5c4cc40edd..939d093946 100644 --- a/core/rawdb/freezer_table_test.go +++ b/core/rawdb/freezer_table_test.go @@ -994,6 +994,52 @@ func TestSequentialReadByteLimit(t *testing.T) { } } +// TestSequentialReadNoByteLimit tests the batch-read if maxBytes is not specified. +// Freezer should return the requested items regardless the size limitation. +func TestSequentialReadNoByteLimit(t *testing.T) { + rm, wm, sg := metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge() + fname := fmt.Sprintf("batchread-3-%d", rand.Uint64()) + { // Fill table + f, err := newTable(os.TempDir(), fname, rm, wm, sg, 100, true, false) + if err != nil { + t.Fatal(err) + } + // Write 10 bytes 30 times, + // Splitting it at every 100 bytes (10 items) + writeChunks(t, f, 30, 10) + f.Close() + } + for i, tc := range []struct { + items uint64 + want int + }{ + {1, 1}, + {30, 30}, + {31, 30}, + } { + { + f, err := newTable(os.TempDir(), fname, rm, wm, sg, 100, true, false) + if err != nil { + t.Fatal(err) + } + items, err := f.RetrieveItems(0, tc.items, 0) + if err != nil { + t.Fatal(err) + } + if have, want := len(items), tc.want; have != want { + t.Fatalf("test %d: want %d items, have %d ", i, want, have) + } + for ii, have := range items { + want := getChunk(10, ii) + if !bytes.Equal(want, have) { + t.Fatalf("test %d: data corruption item %d: have\n%x\n, want \n%x\n", i, ii, have, want) + } + } + f.Close() + } + } +} + func TestFreezerReadonly(t *testing.T) { tmpdir := os.TempDir() // Case 1: Check it fails on non-existent file. diff --git a/core/rawdb/freezer_test.go b/core/rawdb/freezer_test.go index 630c9029b0..96d24cc947 100644 --- a/core/rawdb/freezer_test.go +++ b/core/rawdb/freezer_test.go @@ -192,7 +192,7 @@ func TestFreezerConcurrentModifyTruncate(t *testing.T) { for i := 0; i < 10; i++ { // First reset and write 100 items. - if err := f.TruncateHead(0); err != nil { + if _, err := f.TruncateHead(0); err != nil { t.Fatal("truncate failed:", err) } _, err := f.ModifyAncients(func(op ethdb.AncientWriteOp) error { @@ -227,7 +227,7 @@ func TestFreezerConcurrentModifyTruncate(t *testing.T) { wg.Done() }() go func() { - truncateErr = f.TruncateHead(10) + _, truncateErr = f.TruncateHead(10) wg.Done() }() go func() { diff --git a/core/rawdb/freezer_utils.go b/core/rawdb/freezer_utils.go index e7cce2920d..1bbb50c498 100644 --- a/core/rawdb/freezer_utils.go +++ b/core/rawdb/freezer_utils.go @@ -117,3 +117,19 @@ func truncateFreezerFile(file *os.File, size int64) error { } return nil } + +// grow prepares the slice space for new item, and doubles the slice capacity +// if space is not enough. +func grow(buf []byte, n int) []byte { + if cap(buf)-len(buf) < n { + newcap := 2 * cap(buf) + if newcap-len(buf) < n { + newcap = len(buf) + n + } + nbuf := make([]byte, len(buf), newcap) + copy(nbuf, buf) + buf = nbuf + } + buf = buf[:len(buf)+n] + return buf +} diff --git a/core/rawdb/schema.go b/core/rawdb/schema.go index 18722ed5d4..7269fe5d56 100644 --- a/core/rawdb/schema.go +++ b/core/rawdb/schema.go @@ -43,6 +43,9 @@ var ( // headFinalizedBlockKey tracks the latest known finalized block hash. headFinalizedBlockKey = []byte("LastFinalized") + // persistentStateIDKey tracks the id of latest stored state(for path-based only). + persistentStateIDKey = []byte("LastStateID") + // lastPivotKey tracks the last pivot block used by fast sync (to reenable on sethead). lastPivotKey = []byte("LastPivot") @@ -70,6 +73,9 @@ var ( // skeletonSyncStatusKey tracks the skeleton sync status across restarts. skeletonSyncStatusKey = []byte("SkeletonSyncStatus") + // trieJournalKey tracks the in-memory trie node layers across restarts. + trieJournalKey = []byte("TrieJournal") + // txIndexTailKey tracks the oldest block whose transactions have been indexed. txIndexTailKey = []byte("TransactionIndexTail") @@ -104,6 +110,7 @@ var ( // Path-based storage scheme of merkle patricia trie. 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 configPrefix = []byte("ethereum-config-") // config prefix for the db @@ -188,7 +195,11 @@ func accountSnapshotKey(hash common.Hash) []byte { // storageSnapshotKey = SnapshotStoragePrefix + account hash + storage hash func storageSnapshotKey(accountHash, storageHash common.Hash) []byte { - return append(append(SnapshotStoragePrefix, accountHash.Bytes()...), storageHash.Bytes()...) + buf := make([]byte, len(SnapshotStoragePrefix)+common.HashLength+common.HashLength) + n := copy(buf, SnapshotStoragePrefix) + n += copy(buf[n:], accountHash.Bytes()) + copy(buf[n:], storageHash.Bytes()) + return buf } // storageSnapshotsKey = SnapshotStoragePrefix + account hash + storage hash @@ -240,6 +251,11 @@ func genesisStateSpecKey(hash common.Hash) []byte { return append(genesisPrefix, hash.Bytes()...) } +// stateIDKey = stateIDPrefix + root (32 bytes) +func stateIDKey(root common.Hash) []byte { + return append(stateIDPrefix, root.Bytes()...) +} + // accountTrieNodeKey = trieNodeAccountPrefix + nodePath. func accountTrieNodeKey(path []byte) []byte { return append(trieNodeAccountPrefix, path...) @@ -247,7 +263,11 @@ func accountTrieNodeKey(path []byte) []byte { // storageTrieNodeKey = trieNodeStoragePrefix + accountHash + nodePath. func storageTrieNodeKey(accountHash common.Hash, path []byte) []byte { - return append(append(trieNodeStoragePrefix, accountHash.Bytes()...), path...) + 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 } // IsLegacyTrieNode reports whether a provided database entry is a legacy trie @@ -261,9 +281,10 @@ func IsLegacyTrieNode(key []byte, val []byte) bool { return bytes.Equal(key, crypto.Keccak256(val)) } -// IsAccountTrieNode reports whether a provided database entry is an account -// trie node in path-based state scheme. -func IsAccountTrieNode(key []byte) (bool, []byte) { +// ResolveAccountTrieNodeKey reports whether a provided database entry is an +// 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) { return false, nil } @@ -276,9 +297,17 @@ func IsAccountTrieNode(key []byte) (bool, []byte) { return true, key[len(trieNodeAccountPrefix):] } -// IsStorageTrieNode reports whether a provided database entry is a storage +// IsAccountTrieNode reports whether a provided database entry is an account // trie node in path-based state scheme. -func IsStorageTrieNode(key []byte) (bool, common.Hash, []byte) { +func IsAccountTrieNode(key []byte) bool { + ok, _ := ResolveAccountTrieNodeKey(key) + return ok +} + +// ResolveStorageTrieNode reports whether a provided database entry is a storage +// 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) { return false, common.Hash{}, nil } @@ -294,3 +323,10 @@ func IsStorageTrieNode(key []byte) (bool, common.Hash, []byte) { 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 +// trie node in path-based state scheme. +func IsStorageTrieNode(key []byte) bool { + ok, _, _ := ResolveStorageTrieNode(key) + return ok +} diff --git a/core/rawdb/table.go b/core/rawdb/table.go index 6d6fa0555d..1895f61da2 100644 --- a/core/rawdb/table.go +++ b/core/rawdb/table.go @@ -97,13 +97,13 @@ func (t *table) ReadAncients(fn func(reader ethdb.AncientReaderOp) error) (err e // TruncateHead is a noop passthrough that just forwards the request to the underlying // database. -func (t *table) TruncateHead(items uint64) error { +func (t *table) TruncateHead(items uint64) (uint64, error) { return t.db.TruncateHead(items) } // TruncateTail is a noop passthrough that just forwards the request to the underlying // database. -func (t *table) TruncateTail(items uint64) error { +func (t *table) TruncateTail(items uint64) (uint64, error) { return t.db.TruncateTail(items) } diff --git a/core/state/database.go b/core/state/database.go index ace462165c..9467c8f72e 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -24,6 +24,7 @@ import ( "github.com/ethereum/go-ethereum/common/lru" "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/trie" "github.com/ethereum/go-ethereum/trie/trienode" @@ -43,21 +44,21 @@ type Database interface { OpenTrie(root common.Hash) (Trie, error) // OpenStorageTrie opens the storage trie of an account. - OpenStorageTrie(stateRoot common.Hash, addrHash, root common.Hash) (Trie, error) + OpenStorageTrie(stateRoot common.Hash, address common.Address, root common.Hash) (Trie, error) // CopyTrie returns an independent copy of the given trie. CopyTrie(Trie) Trie // ContractCode retrieves a particular contract's code. - ContractCode(addrHash, codeHash common.Hash) ([]byte, error) + ContractCode(addr common.Address, codeHash common.Hash) ([]byte, error) // ContractCodeSize retrieves a particular contracts code's size. - ContractCodeSize(addrHash, codeHash common.Hash) (int, error) + ContractCodeSize(addr common.Address, codeHash common.Hash) (int, error) // DiskDB returns the underlying key-value disk database. DiskDB() ethdb.KeyValueStore - // TrieDB retrieves the low level trie database used for data storage. + // TrieDB returns the underlying trie database for managing trie nodes. TrieDB() *trie.Database } @@ -93,6 +94,10 @@ type Trie interface { // in the trie with provided address. UpdateAccount(address common.Address, account *types.StateAccount) error + // UpdateContractCode abstracts code write to the trie. It is expected + // to be moved to the stateWriter interface when the latter is ready. + UpdateContractCode(address common.Address, codeHash common.Hash, code []byte) error + // DeleteStorage removes any existing value for key from the trie. If a node // was not found in the database, a trie.MissingNodeError is returned. DeleteStorage(addr common.Address, key []byte) error @@ -110,11 +115,12 @@ 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) + Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) // NodeIterator returns an iterator that returns nodes of the trie. Iteration - // starts at the key after the given start key. - NodeIterator(startKey []byte) trie.NodeIterator + // starts at the key after the given start key. And error will be returned + // if fails to create node iterator. + NodeIterator(startKey []byte) (trie.NodeIterator, error) // Prove constructs a Merkle proof for key. The result contains all encoded nodes // on the path to the value at key. The value itself is also included in the last @@ -123,7 +129,7 @@ type Trie interface { // If the trie does not contain a value for key, the returned proof contains all // 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, fromLevel uint, proofDb ethdb.KeyValueWriter) error + Prove(key []byte, proofDb ethdb.KeyValueWriter) error } // NewDatabase creates a backing store for state. The returned database is safe for @@ -141,7 +147,7 @@ func NewDatabaseWithConfig(db ethdb.Database, config *trie.Config) Database { disk: db, codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize), codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize), - triedb: trie.NewDatabaseWithConfig(db, config), + triedb: trie.NewDatabase(db, config), } } @@ -172,8 +178,8 @@ func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) { } // OpenStorageTrie opens the storage trie of an account. -func (db *cachingDB) OpenStorageTrie(stateRoot common.Hash, addrHash, root common.Hash) (Trie, error) { - tr, err := trie.NewStateTrie(trie.StorageTrieID(stateRoot, addrHash, root), db.triedb) +func (db *cachingDB) OpenStorageTrie(stateRoot common.Hash, address common.Address, root common.Hash) (Trie, error) { + tr, err := trie.NewStateTrie(trie.StorageTrieID(stateRoot, crypto.Keccak256Hash(address.Bytes()), root), db.triedb) if err != nil { return nil, err } @@ -191,7 +197,7 @@ func (db *cachingDB) CopyTrie(t Trie) Trie { } // ContractCode retrieves a particular contract's code. -func (db *cachingDB) ContractCode(addrHash, 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 @@ -208,7 +214,7 @@ func (db *cachingDB) ContractCode(addrHash, codeHash common.Hash) ([]byte, error // 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(addrHash, 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 @@ -223,11 +229,11 @@ func (db *cachingDB) ContractCodeWithPrefix(addrHash, codeHash common.Hash) ([]b } // ContractCodeSize retrieves a particular contracts code's size. -func (db *cachingDB) ContractCodeSize(addrHash, 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 } - code, err := db.ContractCode(addrHash, codeHash) + code, err := db.ContractCode(addr, codeHash) return len(code), err } diff --git a/core/state/dump.go b/core/state/dump.go index d834cbad37..9ce6cd394b 100644 --- a/core/state/dump.go +++ b/core/state/dump.go @@ -44,7 +44,7 @@ type DumpCollector interface { // OnRoot is called with the state root OnRoot(common.Hash) // OnAccount is called once for each account in the trie - OnAccount(common.Address, DumpAccount) + OnAccount(*common.Address, DumpAccount) } // DumpAccount represents an account in the state. @@ -72,8 +72,10 @@ func (d *Dump) OnRoot(root common.Hash) { } // OnAccount implements DumpCollector interface -func (d *Dump) OnAccount(addr common.Address, account DumpAccount) { - d.Accounts[addr] = account +func (d *Dump) OnAccount(addr *common.Address, account DumpAccount) { + if addr != nil { + d.Accounts[*addr] = account + } } // IteratorDump is an implementation for iterating over data. @@ -89,8 +91,10 @@ func (d *IteratorDump) OnRoot(root common.Hash) { } // OnAccount implements DumpCollector interface -func (d *IteratorDump) OnAccount(addr common.Address, account DumpAccount) { - d.Accounts[addr] = account +func (d *IteratorDump) OnAccount(addr *common.Address, account DumpAccount) { + if addr != nil { + d.Accounts[*addr] = account + } } // iterativeDump is a DumpCollector-implementation which dumps output line-by-line iteratively. @@ -99,7 +103,7 @@ type iterativeDump struct { } // OnAccount implements DumpCollector interface -func (d iterativeDump) OnAccount(addr common.Address, account DumpAccount) { +func (d iterativeDump) OnAccount(addr *common.Address, account DumpAccount) { dumpAccount := &DumpAccount{ Balance: account.Balance, Nonce: account.Nonce, @@ -108,10 +112,7 @@ func (d iterativeDump) OnAccount(addr common.Address, account DumpAccount) { Code: account.Code, Storage: account.Storage, SecureKey: account.SecureKey, - Address: nil, - } - if addr != (common.Address{}) { - dumpAccount.Address = &addr + Address: addr, } d.Encode(dumpAccount) } @@ -139,7 +140,11 @@ func (s *StateDB) DumpToCollector(c DumpCollector, conf *DumpConfig) (nextKey [] log.Info("Trie dumping started", "root", s.trie.Hash()) c.OnRoot(s.trie.Hash()) - it := trie.NewIterator(s.trie.NodeIterator(conf.Start)) + trieIt, err := s.trie.NodeIterator(conf.Start) + if err != nil { + return nil + } + it := trie.NewIterator(trieIt) for it.Next() { var data types.StateAccount if err := rlp.DecodeBytes(it.Value, &data); err != nil { @@ -152,28 +157,37 @@ func (s *StateDB) DumpToCollector(c DumpCollector, conf *DumpConfig) (nextKey [] CodeHash: data.CodeHash, SecureKey: it.Key, } - addrBytes := s.trie.GetKey(it.Key) + var ( + addrBytes = s.trie.GetKey(it.Key) + addr = common.BytesToAddress(addrBytes) + address *common.Address + ) if addrBytes == nil { // Preimage missing missingPreimages++ if conf.OnlyWithAddresses { continue } - account.SecureKey = it.Key + } else { + address = &addr } - addr := common.BytesToAddress(addrBytes) - obj := newObject(s, addr, data) + obj := newObject(s, addr, &data) if !conf.SkipCode { - account.Code = obj.Code(s.db) + account.Code = obj.Code() } if !conf.SkipStorage { account.Storage = make(map[common.Hash]string) - tr, err := obj.getTrie(s.db) + tr, err := obj.getTrie() if err != nil { log.Error("Failed to load storage trie", "err", err) continue } - storageIt := trie.NewIterator(tr.NodeIterator(nil)) + trieIt, err := tr.NodeIterator(nil) + if err != nil { + log.Error("Failed to create trie iterator", "err", err) + continue + } + storageIt := trie.NewIterator(trieIt) for storageIt.Next() { _, content, _, err := rlp.Split(storageIt.Value) if err != nil { @@ -183,7 +197,7 @@ func (s *StateDB) DumpToCollector(c DumpCollector, conf *DumpConfig) (nextKey [] account.Storage[common.BytesToHash(s.trie.GetKey(storageIt.Key))] = common.Bytes2Hex(content) } } - c.OnAccount(addr, account) + c.OnAccount(address, account) accounts++ if time.Since(logged) > 8*time.Second { log.Info("Trie dumping in progress", "at", it.Key, "accounts", accounts, diff --git a/core/state/iterator.go b/core/state/iterator.go index 79bb650abc..683efd73de 100644 --- a/core/state/iterator.go +++ b/core/state/iterator.go @@ -18,6 +18,7 @@ package state import ( "bytes" + "errors" "fmt" "github.com/ethereum/go-ethereum/common" @@ -27,7 +28,8 @@ import ( ) // nodeIterator is an iterator to traverse the entire state trie post-order, -// including all of the contract code and contract state tries. +// including all of the contract code and contract state tries. Preimage is +// required in order to resolve the contract address. type nodeIterator struct { state *StateDB // State being iterated @@ -74,8 +76,12 @@ func (it *nodeIterator) step() error { return nil } // Initialize the iterator if we've just started + var err error if it.stateIt == nil { - it.stateIt = it.state.trie.NodeIterator(nil) + it.stateIt, err = it.state.trie.NodeIterator(nil) + if err != nil { + return err + } } // If we had data nodes previously, we surely have at least state nodes if it.dataIt != nil { @@ -106,21 +112,31 @@ func (it *nodeIterator) step() error { } // Otherwise we've reached an account node, initiate data iteration var account types.StateAccount - if err := rlp.Decode(bytes.NewReader(it.stateIt.LeafBlob()), &account); err != nil { + if err := rlp.DecodeBytes(it.stateIt.LeafBlob(), &account); err != nil { return err } - dataTrie, err := it.state.db.OpenStorageTrie(it.state.originalRoot, common.BytesToHash(it.stateIt.LeafKey()), account.Root) + // Lookup the preimage of account hash + preimage := it.state.trie.GetKey(it.stateIt.LeafKey()) + if preimage == nil { + return errors.New("account address is not available") + } + address := common.BytesToAddress(preimage) + + // Traverse the storage slots belong to the account + dataTrie, err := it.state.db.OpenStorageTrie(it.state.originalRoot, address, account.Root) + if err != nil { + return err + } + it.dataIt, err = dataTrie.NodeIterator(nil) if err != nil { return err } - it.dataIt = dataTrie.NodeIterator(nil) if !it.dataIt.Next(true) { it.dataIt = nil } if !bytes.Equal(account.CodeHash, types.EmptyCodeHash.Bytes()) { it.codeHash = common.BytesToHash(account.CodeHash) - addrHash := common.BytesToHash(it.stateIt.LeafKey()) - it.code, err = it.state.db.ContractCode(addrHash, common.BytesToHash(account.CodeHash)) + it.code, err = it.state.db.ContractCode(address, common.BytesToHash(account.CodeHash)) if err != nil { return fmt.Errorf("code %x: %v", account.CodeHash, err) } diff --git a/core/state/iterator_test.go b/core/state/iterator_test.go index c8e1a181eb..73cc22490b 100644 --- a/core/state/iterator_test.go +++ b/core/state/iterator_test.go @@ -26,9 +26,14 @@ import ( // Tests that the node iterator indeed walks over the entire database contents. func TestNodeIteratorCoverage(t *testing.T) { + testNodeIteratorCoverage(t, rawdb.HashScheme) + testNodeIteratorCoverage(t, rawdb.PathScheme) +} + +func testNodeIteratorCoverage(t *testing.T, scheme string) { // Create some arbitrary test state to iterate - db, sdb, root, _ := makeTestState() - sdb.TrieDB().Commit(root, false) + db, sdb, ndb, root, _ := makeTestState(scheme) + ndb.Commit(root, false) state, err := New(root, sdb, nil) if err != nil { @@ -48,7 +53,7 @@ func TestNodeIteratorCoverage(t *testing.T) { ) it := db.NewIterator(nil, nil) for it.Next() { - ok, hash := isTrieNode(sdb.TrieDB().Scheme(), it.Key(), it.Value()) + ok, hash := isTrieNode(scheme, it.Key(), it.Value()) if !ok { continue } @@ -90,11 +95,11 @@ func isTrieNode(scheme string, key, val []byte) (bool, common.Hash) { return true, common.BytesToHash(key) } } else { - ok, _ := rawdb.IsAccountTrieNode(key) + ok := rawdb.IsAccountTrieNode(key) if ok { return true, crypto.Keccak256Hash(val) } - ok, _, _ = rawdb.IsStorageTrieNode(key) + ok = rawdb.IsStorageTrieNode(key) if ok { return true, crypto.Keccak256Hash(val) } diff --git a/core/state/journal.go b/core/state/journal.go index 1722fb4c02..137ec76395 100644 --- a/core/state/journal.go +++ b/core/state/journal.go @@ -90,12 +90,19 @@ type ( 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 } - suicideChange struct { + selfDestructChange struct { account *common.Address - prev bool // whether account had already suicided + prev bool // whether account had already self-destructed prevbalance *big.Int } @@ -159,21 +166,33 @@ func (ch resetObjectChange) revert(s *StateDB) { 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 resetObjectChange) dirtied() *common.Address { - return nil + return ch.account } -func (ch suicideChange) revert(s *StateDB) { +func (ch selfDestructChange) revert(s *StateDB) { obj := s.getStateObject(*ch.account) if obj != nil { - obj.suicided = ch.prev + obj.selfDestructed = ch.prev obj.setBalance(ch.prevbalance) } } -func (ch suicideChange) dirtied() *common.Address { +func (ch selfDestructChange) dirtied() *common.Address { return ch.account } diff --git a/core/state/metrics.go b/core/state/metrics.go index e702ef3a81..64c651461e 100644 --- a/core/state/metrics.go +++ b/core/state/metrics.go @@ -27,4 +27,11 @@ 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) + slotDeletionSkip = metrics.NewRegisteredGauge("state/delete/storage/skip", nil) ) diff --git a/core/state/pruner/bloom.go b/core/state/pruner/bloom.go index 72315db720..9f068eaf2d 100644 --- a/core/state/pruner/bloom.go +++ b/core/state/pruner/bloom.go @@ -127,6 +127,6 @@ func (bloom *stateBloom) Delete(key []byte) error { panic("not supported") } // reports whether the key is contained. // - If it says yes, the key may be contained // - If it says no, the key is definitely not contained. -func (bloom *stateBloom) Contain(key []byte) (bool, error) { - return bloom.bloom.Contains(stateBloomHasher(key)), nil +func (bloom *stateBloom) Contain(key []byte) bool { + return bloom.bloom.Contains(stateBloomHasher(key)) } diff --git a/core/state/pruner/pruner.go b/core/state/pruner/pruner.go index 2bd5658e0a..5acf54f642 100644 --- a/core/state/pruner/pruner.go +++ b/core/state/pruner/pruner.go @@ -57,7 +57,6 @@ const ( // Config includes all the configurations for pruning. type Config struct { Datadir string // The directory of the state database - Cachedir string // The directory of state clean cache BloomSize uint64 // The Megabytes of memory allocated to bloom-filter } @@ -86,13 +85,16 @@ func NewPruner(db ethdb.Database, config Config) (*Pruner, error) { if headBlock == nil { return nil, errors.New("failed to load head block") } + // Offline pruning is only supported in legacy hash based scheme. + triedb := trie.NewDatabase(db, trie.HashDefaults) + snapconfig := snapshot.Config{ CacheSize: 256, Recovery: false, NoBuild: true, AsyncBuild: false, } - snaptree, err := snapshot.New(snapconfig, db, trie.NewDatabase(db), headBlock.Root()) + snaptree, err := snapshot.New(snapconfig, db, triedb, headBlock.Root()) if err != nil { return nil, err // The relevant snapshot(s) might not exist } @@ -146,9 +148,7 @@ func prune(snaptree *snapshot.Tree, root common.Hash, maindb ethdb.Database, sta if _, exist := middleStateRoots[common.BytesToHash(checkKey)]; exist { log.Debug("Forcibly delete the middle state roots", "hash", common.BytesToHash(checkKey)) } else { - if ok, err := stateBloom.Contain(checkKey); err != nil { - return err - } else if ok { + if stateBloom.Contain(checkKey) { continue } } @@ -243,7 +243,7 @@ func (p *Pruner) Prune(root common.Hash) error { return err } if stateBloomRoot != (common.Hash{}) { - return RecoverPruning(p.config.Datadir, p.db, p.config.Cachedir) + return RecoverPruning(p.config.Datadir, p.db) } // If the target state root is not specified, use the HEAD-127 as the // target. The reason for picking it is: @@ -268,7 +268,7 @@ 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(rinkeby, goerli + // 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 @@ -301,12 +301,6 @@ func (p *Pruner) Prune(root common.Hash) error { log.Info("Selecting user-specified state as the pruning target", "root", root) } } - // Before start the pruning, delete the clean trie cache first. - // It's necessary otherwise in the next restart we will hit the - // deleted state root in the "clean cache" so that the incomplete - // state is picked for usage. - deleteCleanTrieCache(p.config.Cachedir) - // All the state roots of the middle layer should be forcibly pruned, // otherwise the dangling state will be left. middleRoots := make(map[common.Hash]struct{}) @@ -344,7 +338,7 @@ func (p *Pruner) Prune(root common.Hash) error { // pruning can be resumed. What's more if the bloom filter is constructed, the // pruning **has to be resumed**. Otherwise a lot of dangling nodes may be left // in the disk. -func RecoverPruning(datadir string, db ethdb.Database, trieCachePath string) error { +func RecoverPruning(datadir string, db ethdb.Database) error { stateBloomPath, stateBloomRoot, err := findBloomFilter(datadir) if err != nil { return err @@ -370,7 +364,9 @@ func RecoverPruning(datadir string, db ethdb.Database, trieCachePath string) err NoBuild: true, AsyncBuild: false, } - snaptree, err := snapshot.New(snapconfig, db, trie.NewDatabase(db), headBlock.Root()) + // Offline pruning is only supported in legacy hash based scheme. + triedb := trie.NewDatabase(db, trie.HashDefaults) + snaptree, err := snapshot.New(snapconfig, db, triedb, headBlock.Root()) if err != nil { return err // The relevant snapshot(s) might not exist } @@ -380,12 +376,6 @@ func RecoverPruning(datadir string, db ethdb.Database, trieCachePath string) err } log.Info("Loaded state bloom filter", "path", stateBloomPath) - // Before start the pruning, delete the clean trie cache first. - // It's necessary otherwise in the next restart we will hit the - // deleted state root in the "clean cache" so that the incomplete - // state is picked for usage. - deleteCleanTrieCache(trieCachePath) - // All the state roots of the middle layers should be forcibly pruned, // otherwise the dangling state will be left. var ( @@ -418,11 +408,14 @@ func extractGenesis(db ethdb.Database, stateBloom *stateBloom) error { if genesis == nil { return errors.New("missing genesis block") } - t, err := trie.NewStateTrie(trie.StateTrieID(genesis.Root()), trie.NewDatabase(db)) + t, err := trie.NewStateTrie(trie.StateTrieID(genesis.Root()), trie.NewDatabase(db, trie.HashDefaults)) + if err != nil { + return err + } + accIter, err := t.NodeIterator(nil) if err != nil { return err } - accIter := t.NodeIterator(nil) for accIter.Next(true) { hash := accIter.Hash() @@ -439,11 +432,14 @@ func extractGenesis(db ethdb.Database, stateBloom *stateBloom) error { } if acc.Root != types.EmptyRootHash { id := trie.StorageTrieID(genesis.Root(), common.BytesToHash(accIter.LeafKey()), acc.Root) - storageTrie, err := trie.NewStateTrie(id, trie.NewDatabase(db)) + storageTrie, err := trie.NewStateTrie(id, trie.NewDatabase(db, trie.HashDefaults)) + if err != nil { + return err + } + storageIter, err := storageTrie.NodeIterator(nil) if err != nil { return err } - storageIter := storageTrie.NodeIterator(nil) for storageIter.Next(true) { hash := storageIter.Hash() if hash != (common.Hash{}) { @@ -493,23 +489,3 @@ func findBloomFilter(datadir string) (string, common.Hash, error) { } return stateBloomPath, stateBloomRoot, nil } - -const warningLog = ` - -WARNING! - -The clean trie cache is not found. Please delete it by yourself after the -pruning. Remember don't start the Geth without deleting the clean trie cache -otherwise the entire database may be damaged! - -Check the command description "geth snapshot prune-state --help" for more details. -` - -func deleteCleanTrieCache(path string) { - if !common.FileExist(path) { - log.Warn(warningLog) - return - } - os.RemoveAll(path) - log.Info("Deleted trie clean cache", "path", path) -} diff --git a/core/state/snapshot/account.go b/core/state/snapshot/account.go deleted file mode 100644 index b5634972ad..0000000000 --- a/core/state/snapshot/account.go +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2019 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package snapshot - -import ( - "bytes" - "math/big" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/rlp" -) - -// Account is a modified version of a state.Account, where the root is replaced -// with a byte slice. This format can be used to represent full-consensus format -// or slim-snapshot format which replaces the empty root and code hash as nil -// byte slice. -type Account struct { - Nonce uint64 - Balance *big.Int - Root []byte - CodeHash []byte -} - -// SlimAccount converts a state.Account content into a slim snapshot account -func SlimAccount(nonce uint64, balance *big.Int, root common.Hash, codehash []byte) Account { - slim := Account{ - Nonce: nonce, - Balance: balance, - } - if root != types.EmptyRootHash { - slim.Root = root[:] - } - if !bytes.Equal(codehash, types.EmptyCodeHash[:]) { - slim.CodeHash = codehash - } - return slim -} - -// SlimAccountRLP converts a state.Account content into a slim snapshot -// version RLP encoded. -func SlimAccountRLP(nonce uint64, balance *big.Int, root common.Hash, codehash []byte) []byte { - data, err := rlp.EncodeToBytes(SlimAccount(nonce, balance, root, codehash)) - if err != nil { - panic(err) - } - return data -} - -// FullAccount decodes the data on the 'slim RLP' format and return -// the consensus format account. -func FullAccount(data []byte) (Account, error) { - var account Account - if err := rlp.DecodeBytes(data, &account); err != nil { - return Account{}, err - } - if len(account.Root) == 0 { - account.Root = types.EmptyRootHash[:] - } - if len(account.CodeHash) == 0 { - account.CodeHash = types.EmptyCodeHash[:] - } - return account, nil -} - -// FullAccountRLP converts data on the 'slim RLP' format into the full RLP-format. -func FullAccountRLP(data []byte) ([]byte, error) { - account, err := FullAccount(data) - if err != nil { - return nil, err - } - return rlp.EncodeToBytes(account) -} diff --git a/core/state/snapshot/conversion.go b/core/state/snapshot/conversion.go index 0e583e6269..1e683f76ce 100644 --- a/core/state/snapshot/conversion.go +++ b/core/state/snapshot/conversion.go @@ -17,7 +17,6 @@ package snapshot import ( - "bytes" "encoding/binary" "errors" "fmt" @@ -301,7 +300,7 @@ func generateTrieRoot(db ethdb.KeyValueWriter, scheme string, it Iterator, accou fullData []byte ) if leafCallback == nil { - fullData, err = FullAccountRLP(it.(AccountIterator).Account()) + fullData, err = types.FullAccountRLP(it.(AccountIterator).Account()) if err != nil { return stop(err) } @@ -313,7 +312,7 @@ func generateTrieRoot(db ethdb.KeyValueWriter, scheme string, it Iterator, accou return stop(err) } // Fetch the next account and process it concurrently - account, err := FullAccount(it.(AccountIterator).Account()) + account, err := types.FullAccount(it.(AccountIterator).Account()) if err != nil { return stop(err) } @@ -323,7 +322,7 @@ func generateTrieRoot(db ethdb.KeyValueWriter, scheme string, it Iterator, accou results <- err return } - if !bytes.Equal(account.Root, subroot.Bytes()) { + if account.Root != subroot { results <- fmt.Errorf("invalid subroot(path %x), want %x, have %x", hash, account.Root, subroot) return } diff --git a/core/state/snapshot/difflayer.go b/core/state/snapshot/difflayer.go index 4701acccd3..b6aca599c5 100644 --- a/core/state/snapshot/difflayer.go +++ b/core/state/snapshot/difflayer.go @@ -21,14 +21,15 @@ import ( "fmt" "math" "math/rand" - "sort" "sync" "sync/atomic" "time" "github.com/ethereum/go-ethereum/common" + "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 ( @@ -272,7 +273,7 @@ func (dl *diffLayer) Stale() bool { // Account directly retrieves the account associated with a particular hash in // the snapshot slim data format. -func (dl *diffLayer) Account(hash common.Hash) (*Account, error) { +func (dl *diffLayer) Account(hash common.Hash) (*types.SlimAccount, error) { data, err := dl.AccountRLP(hash) if err != nil { return nil, err @@ -280,7 +281,7 @@ func (dl *diffLayer) Account(hash common.Hash) (*Account, error) { if len(data) == 0 { // can be both nil and []byte{} return nil, nil } - account := new(Account) + account := new(types.SlimAccount) if err := rlp.DecodeBytes(data, account); err != nil { panic(err) } @@ -292,9 +293,14 @@ func (dl *diffLayer) Account(hash common.Hash) (*Account, error) { // // Note the returned account is not a copy, please don't modify it. func (dl *diffLayer) AccountRLP(hash common.Hash) ([]byte, error) { + // Check staleness before reaching further. + dl.lock.RLock() + if dl.Stale() { + dl.lock.RUnlock() + return nil, ErrSnapshotStale + } // Check the bloom filter first whether there's even a point in reaching into // all the maps in all the layers below - dl.lock.RLock() hit := dl.diffed.Contains(accountBloomHasher(hash)) if !hit { hit = dl.diffed.Contains(destructBloomHasher(hash)) @@ -361,6 +367,11 @@ func (dl *diffLayer) Storage(accountHash, storageHash common.Hash) ([]byte, erro // Check the bloom filter first whether there's even a point in reaching into // all the maps in all the layers below dl.lock.RLock() + // Check staleness before reaching further. + if dl.Stale() { + dl.lock.RUnlock() + return nil, ErrSnapshotStale + } hit := dl.diffed.Contains(storageBloomHasher{accountHash, storageHash}) if !hit { hit = dl.diffed.Contains(destructBloomHasher(accountHash)) @@ -514,7 +525,7 @@ func (dl *diffLayer) AccountList() []common.Hash { dl.accountList = append(dl.accountList, hash) } } - sort.Sort(hashes(dl.accountList)) + slices.SortFunc(dl.accountList, common.Hash.Cmp) dl.memory += uint64(len(dl.accountList) * common.HashLength) return dl.accountList } @@ -552,7 +563,7 @@ func (dl *diffLayer) StorageList(accountHash common.Hash) ([]common.Hash, bool) for k := range storageMap { storageList = append(storageList, k) } - sort.Sort(hashes(storageList)) + slices.SortFunc(storageList, common.Hash.Cmp) dl.storageList[accountHash] = storageList dl.memory += uint64(len(dl.storageList)*common.HashLength + common.HashLength) return storageList, destructed diff --git a/core/state/snapshot/disklayer.go b/core/state/snapshot/disklayer.go index 7cbf6e293d..513f0f5aba 100644 --- a/core/state/snapshot/disklayer.go +++ b/core/state/snapshot/disklayer.go @@ -23,6 +23,7 @@ import ( "github.com/VictoriaMetrics/fastcache" "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/ethdb" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" @@ -65,7 +66,7 @@ func (dl *diskLayer) Stale() bool { // Account directly retrieves the account associated with a particular hash in // the snapshot slim data format. -func (dl *diskLayer) Account(hash common.Hash) (*Account, error) { +func (dl *diskLayer) Account(hash common.Hash) (*types.SlimAccount, error) { data, err := dl.AccountRLP(hash) if err != nil { return nil, err @@ -73,7 +74,7 @@ func (dl *diskLayer) Account(hash common.Hash) (*Account, error) { if len(data) == 0 { // can be both nil and []byte{} return nil, nil } - account := new(Account) + account := new(types.SlimAccount) if err := rlp.DecodeBytes(data, account); err != nil { panic(err) } diff --git a/core/state/snapshot/generate.go b/core/state/snapshot/generate.go index 4703b45df3..40264b092c 100644 --- a/core/state/snapshot/generate.go +++ b/core/state/snapshot/generate.go @@ -20,7 +20,6 @@ import ( "bytes" "errors" "fmt" - "math/big" "time" "github.com/VictoriaMetrics/fastcache" @@ -257,7 +256,7 @@ func (dl *diskLayer) proveRange(ctx *generatorContext, trieId *trie.ID, prefix [ if origin == nil { origin = common.Hash{}.Bytes() } - if err := tr.Prove(origin, 0, proof); err != nil { + if err := tr.Prove(origin, proof); err != nil { log.Debug("Failed to prove range", "kind", kind, "origin", origin, "err", err) return &proofResult{ keys: keys, @@ -268,7 +267,7 @@ func (dl *diskLayer) proveRange(ctx *generatorContext, trieId *trie.ID, prefix [ }, nil } if last != nil { - if err := tr.Prove(last, 0, proof); err != nil { + if err := tr.Prove(last, proof); err != nil { log.Debug("Failed to prove range", "kind", kind, "last", last, "err", err) return &proofResult{ keys: keys, @@ -357,14 +356,18 @@ func (dl *diskLayer) generateRange(ctx *generatorContext, trieId *trie.ID, prefi var resolver trie.NodeResolver if len(result.keys) > 0 { mdb := rawdb.NewMemoryDatabase() - tdb := trie.NewDatabase(mdb) + tdb := trie.NewDatabase(mdb, trie.HashDefaults) + defer tdb.Close() snapTrie := trie.NewEmpty(tdb) for i, key := range result.keys { snapTrie.Update(key, result.vals[i]) } - root, nodes := snapTrie.Commit(false) + root, nodes, err := snapTrie.Commit(false) + if err != nil { + return false, nil, err + } if nodes != nil { - tdb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) + tdb.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil) tdb.Commit(root, false) } resolver = func(owner common.Hash, path []byte, hash common.Hash) []byte { @@ -383,8 +386,6 @@ func (dl *diskLayer) generateRange(ctx *generatorContext, trieId *trie.ID, prefi } var ( trieMore bool - nodeIt = tr.NodeIterator(origin) - iter = trie.NewIterator(nodeIt) kvkeys, kvvals = result.keys, result.vals // counters @@ -398,7 +399,12 @@ func (dl *diskLayer) generateRange(ctx *generatorContext, trieId *trie.ID, prefi start = time.Now() internal time.Duration ) + nodeIt, err := tr.NodeIterator(origin) + if err != nil { + return false, nil, err + } nodeIt.AddResolver(resolver) + iter := trie.NewIterator(nodeIt) for iter.Next() { if last != nil && bytes.Compare(iter.Key, last) > 0 { @@ -573,12 +579,7 @@ func generateAccounts(ctx *generatorContext, dl *diskLayer, accMarker []byte) er return nil } // Retrieve the current account and flatten it into the internal format - var acc struct { - Nonce uint64 - Balance *big.Int - Root common.Hash - CodeHash []byte - } + var acc types.StateAccount if err := rlp.DecodeBytes(val, &acc); err != nil { log.Crit("Invalid account encountered during snapshot creation", "err", err) } @@ -594,7 +595,7 @@ func generateAccounts(ctx *generatorContext, dl *diskLayer, accMarker []byte) er } snapRecoveredAccountMeter.Mark(1) } else { - data := SlimAccountRLP(acc.Nonce, acc.Balance, acc.Root, acc.CodeHash) + data := types.SlimAccountRLP(acc) dataLen = len(data) rawdb.WriteAccountSnapshot(ctx.batch, account, data) snapGeneratedAccountMeter.Mark(1) @@ -640,7 +641,7 @@ func generateAccounts(ctx *generatorContext, dl *diskLayer, accMarker []byte) er origin := common.CopyBytes(accMarker) for { id := trie.StateTrieID(dl.root) - exhausted, last, err := dl.generateRange(ctx, id, rawdb.SnapshotAccountPrefix, snapAccount, origin, accountRange, onAccount, 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. } diff --git a/core/state/snapshot/generate_test.go b/core/state/snapshot/generate_test.go index a17ae05e5c..07016b675c 100644 --- a/core/state/snapshot/generate_test.go +++ b/core/state/snapshot/generate_test.go @@ -30,6 +30,8 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" + "github.com/ethereum/go-ethereum/trie/triedb/hashdb" + "github.com/ethereum/go-ethereum/trie/triedb/pathdb" "github.com/ethereum/go-ethereum/trie/trienode" "golang.org/x/crypto/sha3" ) @@ -45,15 +47,20 @@ func hashData(input []byte) common.Hash { // Tests that snapshot generation from an empty database. func TestGeneration(t *testing.T) { + testGeneration(t, rawdb.HashScheme) + testGeneration(t, rawdb.PathScheme) +} + +func testGeneration(t *testing.T, scheme string) { // We can't use statedb to make a test trie (circular dependency), so make // a fake one manually. We're going with a small account trie of 3 accounts, // two of which also has the same 3-slot storage trie attached. - var helper = newHelper() + var helper = newHelper(scheme) stRoot := helper.makeStorageTrie(common.Hash{}, []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, false) - helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) - helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}) - helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) + helper.addTrieAccount("acc-1", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) + helper.addTrieAccount("acc-2", &types.StateAccount{Balance: big.NewInt(2), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) + helper.addTrieAccount("acc-3", &types.StateAccount{Balance: big.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.makeStorageTrie(hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.makeStorageTrie(hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) @@ -79,22 +86,27 @@ func TestGeneration(t *testing.T) { // Tests that snapshot generation with existent flat state. func TestGenerateExistentState(t *testing.T) { + testGenerateExistentState(t, rawdb.HashScheme) + testGenerateExistentState(t, rawdb.PathScheme) +} + +func testGenerateExistentState(t *testing.T, scheme string) { // We can't use statedb to make a test trie (circular dependency), so make // a fake one manually. We're going with a small account trie of 3 accounts, // two of which also has the same 3-slot storage trie attached. - var helper = newHelper() + var helper = newHelper(scheme) stRoot := helper.makeStorageTrie(hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) - helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) - helper.addSnapAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) + helper.addTrieAccount("acc-1", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) + helper.addSnapAccount("acc-1", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addSnapStorage("acc-1", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}) - helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}) - helper.addSnapAccount("acc-2", &Account{Balance: big.NewInt(2), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}) + helper.addTrieAccount("acc-2", &types.StateAccount{Balance: big.NewInt(2), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) + helper.addSnapAccount("acc-2", &types.StateAccount{Balance: big.NewInt(2), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) stRoot = helper.makeStorageTrie(hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) - helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) - helper.addSnapAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) + helper.addTrieAccount("acc-3", &types.StateAccount{Balance: big.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) + helper.addSnapAccount("acc-3", &types.StateAccount{Balance: big.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addSnapStorage("acc-3", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}) root, snap := helper.CommitAndGenerate() @@ -148,9 +160,15 @@ type testHelper struct { nodes *trienode.MergedNodeSet } -func newHelper() *testHelper { +func newHelper(scheme string) *testHelper { diskdb := rawdb.NewMemoryDatabase() - triedb := trie.NewDatabase(diskdb) + config := &trie.Config{} + if scheme == rawdb.PathScheme { + config.PathDB = &pathdb.Config{} // disable caching + } else { + config.HashDB = &hashdb.Config{} // disable caching + } + triedb := trie.NewDatabase(diskdb, config) accTrie, _ := trie.NewStateTrie(trie.StateTrieID(types.EmptyRootHash), triedb) return &testHelper{ diskdb: diskdb, @@ -160,18 +178,17 @@ func newHelper() *testHelper { } } -func (t *testHelper) addTrieAccount(acckey string, acc *Account) { +func (t *testHelper) addTrieAccount(acckey string, acc *types.StateAccount) { val, _ := rlp.EncodeToBytes(acc) t.accTrie.MustUpdate([]byte(acckey), val) } -func (t *testHelper) addSnapAccount(acckey string, acc *Account) { - val, _ := rlp.EncodeToBytes(acc) +func (t *testHelper) addSnapAccount(acckey string, acc *types.StateAccount) { key := hashData([]byte(acckey)) - rawdb.WriteAccountSnapshot(t.diskdb, key, val) + rawdb.WriteAccountSnapshot(t.diskdb, key, types.SlimAccountRLP(*acc)) } -func (t *testHelper) addAccount(acckey string, acc *Account) { +func (t *testHelper) addAccount(acckey string, acc *types.StateAccount) { t.addTrieAccount(acckey, acc) t.addSnapAccount(acckey, acc) } @@ -183,28 +200,28 @@ func (t *testHelper) addSnapStorage(accKey string, keys []string, vals []string) } } -func (t *testHelper) makeStorageTrie(owner common.Hash, keys []string, vals []string, commit bool) []byte { +func (t *testHelper) makeStorageTrie(owner common.Hash, keys []string, vals []string, commit bool) common.Hash { id := trie.StorageTrieID(types.EmptyRootHash, owner, types.EmptyRootHash) stTrie, _ := trie.NewStateTrie(id, t.triedb) for i, k := range keys { stTrie.MustUpdate([]byte(k), []byte(vals[i])) } if !commit { - return stTrie.Hash().Bytes() + return stTrie.Hash() } - root, nodes := stTrie.Commit(false) + root, nodes, _ := stTrie.Commit(false) if nodes != nil { t.nodes.Merge(nodes) } - return root.Bytes() + return root } 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) } - t.triedb.Update(root, types.EmptyRootHash, t.nodes) + t.triedb.Update(root, types.EmptyRootHash, 0, t.nodes, nil) t.triedb.Commit(root, false) return root } @@ -234,31 +251,36 @@ func (t *testHelper) CommitAndGenerate() (common.Hash, *diskLayer) { // - extra slots in the middle // - extra slots in the end func TestGenerateExistentStateWithWrongStorage(t *testing.T) { - helper := newHelper() + testGenerateExistentStateWithWrongStorage(t, rawdb.HashScheme) + testGenerateExistentStateWithWrongStorage(t, rawdb.PathScheme) +} + +func testGenerateExistentStateWithWrongStorage(t *testing.T, scheme string) { + helper := newHelper(scheme) // Account one, empty root but non-empty database - helper.addAccount("acc-1", &Account{Balance: big.NewInt(1), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}) + helper.addAccount("acc-1", &types.StateAccount{Balance: big.NewInt(1), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addSnapStorage("acc-1", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}) // Account two, non empty root but empty database stRoot := helper.makeStorageTrie(hashData([]byte("acc-2")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) - helper.addAccount("acc-2", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) + helper.addAccount("acc-2", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // Miss slots { // Account three, non empty root but misses slots in the beginning helper.makeStorageTrie(hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) - helper.addAccount("acc-3", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) + helper.addAccount("acc-3", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addSnapStorage("acc-3", []string{"key-2", "key-3"}, []string{"val-2", "val-3"}) // Account four, non empty root but misses slots in the middle helper.makeStorageTrie(hashData([]byte("acc-4")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) - helper.addAccount("acc-4", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) + helper.addAccount("acc-4", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addSnapStorage("acc-4", []string{"key-1", "key-3"}, []string{"val-1", "val-3"}) // Account five, non empty root but misses slots in the end helper.makeStorageTrie(hashData([]byte("acc-5")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) - helper.addAccount("acc-5", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) + helper.addAccount("acc-5", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addSnapStorage("acc-5", []string{"key-1", "key-2"}, []string{"val-1", "val-2"}) } @@ -266,22 +288,22 @@ func TestGenerateExistentStateWithWrongStorage(t *testing.T) { { // Account six, non empty root but wrong slots in the beginning helper.makeStorageTrie(hashData([]byte("acc-6")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) - helper.addAccount("acc-6", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) + helper.addAccount("acc-6", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addSnapStorage("acc-6", []string{"key-1", "key-2", "key-3"}, []string{"badval-1", "val-2", "val-3"}) // Account seven, non empty root but wrong slots in the middle helper.makeStorageTrie(hashData([]byte("acc-7")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) - helper.addAccount("acc-7", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) + helper.addAccount("acc-7", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addSnapStorage("acc-7", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "badval-2", "val-3"}) // Account eight, non empty root but wrong slots in the end helper.makeStorageTrie(hashData([]byte("acc-8")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) - helper.addAccount("acc-8", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) + helper.addAccount("acc-8", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addSnapStorage("acc-8", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "badval-3"}) // Account 9, non empty root but rotated slots helper.makeStorageTrie(hashData([]byte("acc-9")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) - helper.addAccount("acc-9", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) + helper.addAccount("acc-9", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addSnapStorage("acc-9", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-3", "val-2"}) } @@ -289,17 +311,17 @@ func TestGenerateExistentStateWithWrongStorage(t *testing.T) { { // Account 10, non empty root but extra slots in the beginning helper.makeStorageTrie(hashData([]byte("acc-10")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) - helper.addAccount("acc-10", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) + helper.addAccount("acc-10", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addSnapStorage("acc-10", []string{"key-0", "key-1", "key-2", "key-3"}, []string{"val-0", "val-1", "val-2", "val-3"}) // Account 11, non empty root but extra slots in the middle helper.makeStorageTrie(hashData([]byte("acc-11")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) - helper.addAccount("acc-11", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) + helper.addAccount("acc-11", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addSnapStorage("acc-11", []string{"key-1", "key-2", "key-2-1", "key-3"}, []string{"val-1", "val-2", "val-2-1", "val-3"}) // Account 12, non empty root but extra slots in the end helper.makeStorageTrie(hashData([]byte("acc-12")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) - helper.addAccount("acc-12", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) + helper.addAccount("acc-12", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addSnapStorage("acc-12", []string{"key-1", "key-2", "key-3", "key-4"}, []string{"val-1", "val-2", "val-3", "val-4"}) } @@ -326,7 +348,12 @@ func TestGenerateExistentStateWithWrongStorage(t *testing.T) { // - wrong accounts // - extra accounts func TestGenerateExistentStateWithWrongAccounts(t *testing.T) { - helper := newHelper() + testGenerateExistentStateWithWrongAccounts(t, rawdb.HashScheme) + testGenerateExistentStateWithWrongAccounts(t, rawdb.PathScheme) +} + +func testGenerateExistentStateWithWrongAccounts(t *testing.T, scheme string) { + helper := newHelper(scheme) helper.makeStorageTrie(hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.makeStorageTrie(hashData([]byte("acc-2")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) @@ -339,25 +366,25 @@ func TestGenerateExistentStateWithWrongAccounts(t *testing.T) { // Missing accounts, only in the trie { - helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // Beginning - helper.addTrieAccount("acc-4", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // Middle - helper.addTrieAccount("acc-6", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // End + helper.addTrieAccount("acc-1", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // Beginning + helper.addTrieAccount("acc-4", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // Middle + helper.addTrieAccount("acc-6", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // End } // Wrong accounts { - helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) - helper.addSnapAccount("acc-2", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: common.Hex2Bytes("0x1234")}) + helper.addTrieAccount("acc-2", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) + helper.addSnapAccount("acc-2", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: common.Hex2Bytes("0x1234")}) - helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) - helper.addSnapAccount("acc-3", &Account{Balance: big.NewInt(1), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}) + helper.addTrieAccount("acc-3", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) + helper.addSnapAccount("acc-3", &types.StateAccount{Balance: big.NewInt(1), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) } // Extra accounts, only in the snap { - helper.addSnapAccount("acc-0", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // before the beginning - helper.addSnapAccount("acc-5", &Account{Balance: big.NewInt(1), Root: types.EmptyRootHash.Bytes(), CodeHash: common.Hex2Bytes("0x1234")}) // Middle - helper.addSnapAccount("acc-7", &Account{Balance: big.NewInt(1), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}) // after the end + helper.addSnapAccount("acc-0", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // before the beginning + helper.addSnapAccount("acc-5", &types.StateAccount{Balance: big.NewInt(1), Root: types.EmptyRootHash, CodeHash: common.Hex2Bytes("0x1234")}) // Middle + helper.addSnapAccount("acc-7", &types.StateAccount{Balance: big.NewInt(1), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) // after the end } root, snap := helper.CommitAndGenerate() @@ -381,20 +408,27 @@ func TestGenerateExistentStateWithWrongAccounts(t *testing.T) { // Tests that snapshot generation errors out correctly in case of a missing trie // node in the account trie. func TestGenerateCorruptAccountTrie(t *testing.T) { + testGenerateCorruptAccountTrie(t, rawdb.HashScheme) + testGenerateCorruptAccountTrie(t, rawdb.PathScheme) +} + +func testGenerateCorruptAccountTrie(t *testing.T, scheme string) { // We can't use statedb to make a test trie (circular dependency), so make // a fake one manually. We're going with a small account trie of 3 accounts, // without any storage slots to keep the test smaller. - helper := newHelper() + helper := newHelper(scheme) - helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}) // 0xc7a30f39aff471c95d8a837497ad0e49b65be475cc0953540f80cfcdbdcd9074 - helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7 - helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}) // 0x19ead688e907b0fab07176120dceec244a72aff2f0aa51e8b827584e378772f4 + helper.addTrieAccount("acc-1", &types.StateAccount{Balance: big.NewInt(1), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) // 0xc7a30f39aff471c95d8a837497ad0e49b65be475cc0953540f80cfcdbdcd9074 + helper.addTrieAccount("acc-2", &types.StateAccount{Balance: big.NewInt(2), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7 + helper.addTrieAccount("acc-3", &types.StateAccount{Balance: big.NewInt(3), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x19ead688e907b0fab07176120dceec244a72aff2f0aa51e8b827584e378772f4 root := helper.Commit() // Root: 0xa04693ea110a31037fb5ee814308a6f1d76bdab0b11676bdf4541d2de55ba978 - // Delete an account trie leaf and ensure the generator chokes - helper.triedb.Commit(root, false) - helper.diskdb.Delete(common.HexToHash("0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7").Bytes()) + // Delete an account trie node and ensure the generator chokes + targetPath := []byte{0xc} + targetHash := common.HexToHash("0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7") + + rawdb.DeleteTrieNode(helper.diskdb, common.Hash{}, targetPath, targetHash, scheme) snap := generateSnapshot(helper.diskdb, helper.triedb, 16, root) select { @@ -415,21 +449,30 @@ func TestGenerateCorruptAccountTrie(t *testing.T) { // trie node for a storage trie. It's similar to internal corruption but it is // handled differently inside the generator. func TestGenerateMissingStorageTrie(t *testing.T) { + testGenerateMissingStorageTrie(t, rawdb.HashScheme) + testGenerateMissingStorageTrie(t, rawdb.PathScheme) +} + +func testGenerateMissingStorageTrie(t *testing.T, scheme string) { // We can't use statedb to make a test trie (circular dependency), so make // a fake one manually. We're going with a small account trie of 3 accounts, // two of which also has the same 3-slot storage trie attached. - helper := newHelper() - - stRoot := helper.makeStorageTrie(hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) // 0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67 - helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e - helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7 + var ( + acc1 = hashData([]byte("acc-1")) + acc3 = hashData([]byte("acc-3")) + helper = newHelper(scheme) + ) + stRoot := helper.makeStorageTrie(hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) // 0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67 + helper.addTrieAccount("acc-1", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e + helper.addTrieAccount("acc-2", &types.StateAccount{Balance: big.NewInt(2), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7 stRoot = helper.makeStorageTrie(hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) - helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2 + helper.addTrieAccount("acc-3", &types.StateAccount{Balance: big.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2 root := helper.Commit() - // Delete a storage trie root and ensure the generator chokes - helper.diskdb.Delete(stRoot) + // Delete storage trie root of account one and three. + rawdb.DeleteTrieNode(helper.diskdb, acc1, nil, stRoot, scheme) + rawdb.DeleteTrieNode(helper.diskdb, acc3, nil, stRoot, scheme) snap := generateSnapshot(helper.diskdb, helper.triedb, 16, root) select { @@ -449,21 +492,29 @@ func TestGenerateMissingStorageTrie(t *testing.T) { // Tests that snapshot generation errors out correctly in case of a missing trie // node in a storage trie. func TestGenerateCorruptStorageTrie(t *testing.T) { + testGenerateCorruptStorageTrie(t, rawdb.HashScheme) + testGenerateCorruptStorageTrie(t, rawdb.PathScheme) +} + +func testGenerateCorruptStorageTrie(t *testing.T, scheme string) { // We can't use statedb to make a test trie (circular dependency), so make // a fake one manually. We're going with a small account trie of 3 accounts, // two of which also has the same 3-slot storage trie attached. - helper := newHelper() + helper := newHelper(scheme) - stRoot := helper.makeStorageTrie(hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) // 0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67 - helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e - helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7 + stRoot := helper.makeStorageTrie(hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) // 0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67 + helper.addTrieAccount("acc-1", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e + helper.addTrieAccount("acc-2", &types.StateAccount{Balance: big.NewInt(2), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7 stRoot = helper.makeStorageTrie(hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) - helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2 + helper.addTrieAccount("acc-3", &types.StateAccount{Balance: big.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2 root := helper.Commit() - // Delete a storage trie leaf and ensure the generator chokes - helper.diskdb.Delete(common.HexToHash("0x18a0f4d79cff4459642dd7604f303886ad9d77c30cf3d7d7cedb3a693ab6d371").Bytes()) + // Delete a node in the storage trie. + targetPath := []byte{0x4} + targetHash := common.HexToHash("0x18a0f4d79cff4459642dd7604f303886ad9d77c30cf3d7d7cedb3a693ab6d371") + rawdb.DeleteTrieNode(helper.diskdb, hashData([]byte("acc-1")), targetPath, targetHash, scheme) + rawdb.DeleteTrieNode(helper.diskdb, hashData([]byte("acc-3")), targetPath, targetHash, scheme) snap := generateSnapshot(helper.diskdb, helper.triedb, 16, root) select { @@ -482,7 +533,12 @@ func TestGenerateCorruptStorageTrie(t *testing.T) { // Tests that snapshot generation when an extra account with storage exists in the snap state. func TestGenerateWithExtraAccounts(t *testing.T) { - helper := newHelper() + testGenerateWithExtraAccounts(t, rawdb.HashScheme) + testGenerateWithExtraAccounts(t, rawdb.PathScheme) +} + +func testGenerateWithExtraAccounts(t *testing.T, scheme string) { + helper := newHelper(scheme) { // Account one in the trie stRoot := helper.makeStorageTrie(hashData([]byte("acc-1")), @@ -490,7 +546,7 @@ func TestGenerateWithExtraAccounts(t *testing.T) { []string{"val-1", "val-2", "val-3", "val-4", "val-5"}, true, ) - acc := &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()} + acc := &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()} val, _ := rlp.EncodeToBytes(acc) helper.accTrie.MustUpdate([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e @@ -510,7 +566,7 @@ func TestGenerateWithExtraAccounts(t *testing.T) { []string{"val-1", "val-2", "val-3", "val-4", "val-5"}, true, ) - acc := &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()} + acc := &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()} val, _ := rlp.EncodeToBytes(acc) key := hashData([]byte("acc-2")) rawdb.WriteAccountSnapshot(helper.diskdb, key, val) @@ -550,10 +606,15 @@ func enableLogging() { // Tests that snapshot generation when an extra account with storage exists in the snap state. func TestGenerateWithManyExtraAccounts(t *testing.T) { + testGenerateWithManyExtraAccounts(t, rawdb.HashScheme) + testGenerateWithManyExtraAccounts(t, rawdb.PathScheme) +} + +func testGenerateWithManyExtraAccounts(t *testing.T, scheme string) { if false { enableLogging() } - helper := newHelper() + helper := newHelper(scheme) { // Account one in the trie stRoot := helper.makeStorageTrie(hashData([]byte("acc-1")), @@ -561,7 +622,7 @@ func TestGenerateWithManyExtraAccounts(t *testing.T) { []string{"val-1", "val-2", "val-3"}, true, ) - acc := &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()} + acc := &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()} val, _ := rlp.EncodeToBytes(acc) helper.accTrie.MustUpdate([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e @@ -575,7 +636,7 @@ func TestGenerateWithManyExtraAccounts(t *testing.T) { { // 100 accounts exist only in snapshot for i := 0; i < 1000; i++ { - acc := &Account{Balance: big.NewInt(int64(i)), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()} + acc := &types.StateAccount{Balance: big.NewInt(int64(i)), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()} val, _ := rlp.EncodeToBytes(acc) key := hashData([]byte(fmt.Sprintf("acc-%d", i))) rawdb.WriteAccountSnapshot(helper.diskdb, key, val) @@ -606,13 +667,18 @@ func TestGenerateWithManyExtraAccounts(t *testing.T) { // So in trie, we iterate 2 entries 0x03, 0x07. We create the 0x07 in the database and abort the procedure, because the trie is exhausted. // But in the database, we still have the stale storage slots 0x04, 0x05. They are not iterated yet, but the procedure is finished. func TestGenerateWithExtraBeforeAndAfter(t *testing.T) { + testGenerateWithExtraBeforeAndAfter(t, rawdb.HashScheme) + testGenerateWithExtraBeforeAndAfter(t, rawdb.PathScheme) +} + +func testGenerateWithExtraBeforeAndAfter(t *testing.T, scheme string) { accountCheckRange = 3 if false { enableLogging() } - helper := newHelper() + helper := newHelper(scheme) { - acc := &Account{Balance: big.NewInt(1), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()} + acc := &types.StateAccount{Balance: big.NewInt(1), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()} val, _ := rlp.EncodeToBytes(acc) helper.accTrie.MustUpdate(common.HexToHash("0x03").Bytes(), val) helper.accTrie.MustUpdate(common.HexToHash("0x07").Bytes(), val) @@ -643,13 +709,18 @@ func TestGenerateWithExtraBeforeAndAfter(t *testing.T) { // TestGenerateWithMalformedSnapdata tests what happes if we have some junk // in the snapshot database, which cannot be parsed back to an account func TestGenerateWithMalformedSnapdata(t *testing.T) { + testGenerateWithMalformedSnapdata(t, rawdb.HashScheme) + testGenerateWithMalformedSnapdata(t, rawdb.PathScheme) +} + +func testGenerateWithMalformedSnapdata(t *testing.T, scheme string) { accountCheckRange = 3 if false { enableLogging() } - helper := newHelper() + helper := newHelper(scheme) { - acc := &Account{Balance: big.NewInt(1), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()} + acc := &types.StateAccount{Balance: big.NewInt(1), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()} val, _ := rlp.EncodeToBytes(acc) helper.accTrie.MustUpdate(common.HexToHash("0x03").Bytes(), val) @@ -680,15 +751,20 @@ func TestGenerateWithMalformedSnapdata(t *testing.T) { } func TestGenerateFromEmptySnap(t *testing.T) { + testGenerateFromEmptySnap(t, rawdb.HashScheme) + testGenerateFromEmptySnap(t, rawdb.PathScheme) +} + +func testGenerateFromEmptySnap(t *testing.T, scheme string) { //enableLogging() accountCheckRange = 10 storageCheckRange = 20 - helper := newHelper() + helper := newHelper(scheme) // Add 1K accounts to the trie for i := 0; i < 400; i++ { stRoot := helper.makeStorageTrie(hashData([]byte(fmt.Sprintf("acc-%d", i))), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.addTrieAccount(fmt.Sprintf("acc-%d", i), - &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) + &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) } root, snap := helper.CommitAndGenerate() t.Logf("Root: %#x\n", root) // Root: 0x6f7af6d2e1a1bf2b84a3beb3f8b64388465fbc1e274ca5d5d3fc787ca78f59e4 @@ -715,8 +791,13 @@ func TestGenerateFromEmptySnap(t *testing.T) { // This hits a case where the snap verification passes, but there are more elements in the trie // which we must also add. func TestGenerateWithIncompleteStorage(t *testing.T) { + testGenerateWithIncompleteStorage(t, rawdb.HashScheme) + testGenerateWithIncompleteStorage(t, rawdb.PathScheme) +} + +func testGenerateWithIncompleteStorage(t *testing.T, scheme string) { storageCheckRange = 4 - helper := newHelper() + helper := newHelper(scheme) stKeys := []string{"1", "2", "3", "4", "5", "6", "7", "8"} stVals := []string{"v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8"} // We add 8 accounts, each one is missing exactly one of the storage slots. This means @@ -725,7 +806,7 @@ func TestGenerateWithIncompleteStorage(t *testing.T) { for i := 0; i < 8; i++ { accKey := fmt.Sprintf("acc-%d", i) stRoot := helper.makeStorageTrie(hashData([]byte(accKey)), stKeys, stVals, true) - helper.addAccount(accKey, &Account{Balance: big.NewInt(int64(i)), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) + helper.addAccount(accKey, &types.StateAccount{Balance: big.NewInt(int64(i)), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) var moddedKeys []string var moddedVals []string for ii := 0; ii < 8; ii++ { @@ -814,14 +895,19 @@ func populateDangling(disk ethdb.KeyValueStore) { // // This test will populate some dangling storages to see if they can be cleaned up. func TestGenerateCompleteSnapshotWithDanglingStorage(t *testing.T) { - var helper = newHelper() + testGenerateCompleteSnapshotWithDanglingStorage(t, rawdb.HashScheme) + testGenerateCompleteSnapshotWithDanglingStorage(t, rawdb.PathScheme) +} + +func testGenerateCompleteSnapshotWithDanglingStorage(t *testing.T, scheme string) { + var helper = newHelper(scheme) stRoot := helper.makeStorageTrie(hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) - helper.addAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) - helper.addAccount("acc-2", &Account{Balance: big.NewInt(1), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}) + helper.addAccount("acc-1", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) + helper.addAccount("acc-2", &types.StateAccount{Balance: big.NewInt(1), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) helper.makeStorageTrie(hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) - helper.addAccount("acc-3", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) + helper.addAccount("acc-3", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addSnapStorage("acc-1", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}) helper.addSnapStorage("acc-3", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}) @@ -849,14 +935,19 @@ func TestGenerateCompleteSnapshotWithDanglingStorage(t *testing.T) { // // This test will populate some dangling storages to see if they can be cleaned up. func TestGenerateBrokenSnapshotWithDanglingStorage(t *testing.T) { - var helper = newHelper() + testGenerateBrokenSnapshotWithDanglingStorage(t, rawdb.HashScheme) + testGenerateBrokenSnapshotWithDanglingStorage(t, rawdb.PathScheme) +} + +func testGenerateBrokenSnapshotWithDanglingStorage(t *testing.T, scheme string) { + var helper = newHelper(scheme) stRoot := helper.makeStorageTrie(hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) - helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) - helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}) + helper.addTrieAccount("acc-1", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) + helper.addTrieAccount("acc-2", &types.StateAccount{Balance: big.NewInt(2), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) helper.makeStorageTrie(hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) - helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) + helper.addTrieAccount("acc-3", &types.StateAccount{Balance: big.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) populateDangling(helper.diskdb) diff --git a/core/state/snapshot/iterator_fast.go b/core/state/snapshot/iterator_fast.go index 1a042c7cd3..0502d9cf85 100644 --- a/core/state/snapshot/iterator_fast.go +++ b/core/state/snapshot/iterator_fast.go @@ -22,6 +22,7 @@ import ( "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 @@ -32,32 +33,25 @@ type weightedIterator struct { priority int } -// weightedIterators is a set of iterators implementing the sort.Interface. -type weightedIterators []*weightedIterator - -// Len implements sort.Interface, returning the number of active iterators. -func (its weightedIterators) Len() int { return len(its) } - -// Less implements sort.Interface, returning which of two iterators in the stack -// is before the other. -func (its weightedIterators) Less(i, j int) bool { +func (it *weightedIterator) Cmp(other *weightedIterator) int { // Order the iterators primarily by the account hashes - hashI := its[i].it.Hash() - hashJ := its[j].it.Hash() + hashI := it.it.Hash() + hashJ := other.it.Hash() switch bytes.Compare(hashI[:], hashJ[:]) { case -1: - return true + return -1 case 1: - return false + return 1 } // Same account/storage-slot in multiple layers, split by priority - return its[i].priority < its[j].priority -} - -// Swap implements sort.Interface, swapping two entries in the iterator stack. -func (its weightedIterators) Swap(i, j int) { - its[i], its[j] = its[j], its[i] + if it.priority < other.priority { + return -1 + } + if it.priority > other.priority { + return 1 + } + return 0 } // fastIterator is a more optimized multi-layer iterator which maintains a @@ -69,7 +63,7 @@ type fastIterator struct { curAccount []byte curSlot []byte - iterators weightedIterators + iterators []*weightedIterator initiated bool account bool fail error @@ -167,7 +161,7 @@ func (fi *fastIterator) init() { } } // Re-sort the entire list - sort.Sort(fi.iterators) + slices.SortFunc(fi.iterators, func(a, b *weightedIterator) int { return a.Cmp(b) }) fi.initiated = false } diff --git a/core/state/snapshot/journal.go b/core/state/snapshot/journal.go index c1a4cc3d47..4d070208f5 100644 --- a/core/state/snapshot/journal.go +++ b/core/state/snapshot/journal.go @@ -305,7 +305,7 @@ func iterateJournal(db ethdb.KeyValueReader, callback journalCallback) error { } if baseRoot := rawdb.ReadSnapshotRoot(db); baseRoot != parent { log.Warn("Loaded snapshot journal", "diskroot", baseRoot, "diffs", "unmatched") - return fmt.Errorf("mismatched disk and diff layers") + return errors.New("mismatched disk and diff layers") } for { var ( diff --git a/core/state/snapshot/snapshot.go b/core/state/snapshot/snapshot.go index 2e57a059dd..e30a0005cc 100644 --- a/core/state/snapshot/snapshot.go +++ b/core/state/snapshot/snapshot.go @@ -25,6 +25,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/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" @@ -102,7 +103,7 @@ type Snapshot interface { // Account directly retrieves the account associated with a particular hash in // the snapshot slim data format. - Account(hash common.Hash) (*Account, error) + Account(hash common.Hash) (*types.SlimAccount, error) // AccountRLP directly retrieves the account RLP associated with a particular // hash in the snapshot slim data format. @@ -563,7 +564,7 @@ func diffToDisk(bottom *diffLayer) *diskLayer { // Ensure we don't delete too much data blindly (contract can be // huge). It's ok to flush, the root will go missing in case of a // crash and we'll detect and regenerate the snapshot. - if batch.ValueSize() > ethdb.IdealBatchSize { + if batch.ValueSize() > 64*1024*1024 { if err := batch.Write(); err != nil { log.Crit("Failed to write storage deletions", "err", err) } @@ -589,7 +590,7 @@ func diffToDisk(bottom *diffLayer) *diskLayer { // Ensure we don't write too much data blindly. It's ok to flush, the // root will go missing in case of a crash and we'll detect and regen // the snapshot. - if batch.ValueSize() > ethdb.IdealBatchSize { + if batch.ValueSize() > 64*1024*1024 { if err := batch.Write(); err != nil { log.Crit("Failed to write storage deletions", "err", err) } @@ -851,3 +852,21 @@ func (t *Tree) DiskRoot() common.Hash { return t.diskRoot() } + +// Size returns the memory usage of the diff layers above the disk layer and the +// dirty nodes buffered in the disk layer. Currently, the implementation uses a +// special diff layer (the first) as an aggregator simulating a dirty buffer, so +// the second return will always be 0. However, this will be made consistent with +// the pathdb, which will require a second return. +func (t *Tree) Size() (diffs common.StorageSize, buf common.StorageSize) { + t.lock.RLock() + defer t.lock.RUnlock() + + var size common.StorageSize + for _, layer := range t.layers { + if layer, ok := layer.(*diffLayer); ok { + size += common.StorageSize(layer.memory) + } + } + return size, 0 +} diff --git a/core/state/snapshot/snapshot_test.go b/core/state/snapshot/snapshot_test.go index 249da10aa6..b66799757e 100644 --- a/core/state/snapshot/snapshot_test.go +++ b/core/state/snapshot/snapshot_test.go @@ -43,11 +43,10 @@ func randomHash() common.Hash { // randomAccount generates a random account and returns it RLP encoded. func randomAccount() []byte { - root := randomHash() - a := Account{ + a := &types.StateAccount{ Balance: big.NewInt(rand.Int63()), Nonce: rand.Uint64(), - Root: root[:], + Root: randomHash(), CodeHash: types.EmptyCodeHash[:], } data, _ := rlp.EncodeToBytes(a) @@ -185,6 +184,10 @@ func TestDiskLayerExternalInvalidationPartialFlatten(t *testing.T) { // be returned with junk data. This version of the test retains the bottom diff // layer to check the usual mode of operation where the accumulator is retained. func TestDiffLayerExternalInvalidationPartialFlatten(t *testing.T) { + // Un-commenting this triggers the bloom set to be deterministic. The values below + // were used to trigger the flaw described in https://github.com/ethereum/go-ethereum/issues/27254. + // bloomDestructHasherOffset, bloomAccountHasherOffset, bloomStorageHasherOffset = 14, 24, 5 + // Create an empty base layer and a snapshot tree out of it base := &diskLayer{ diskdb: rawdb.NewMemoryDatabase(), @@ -461,7 +464,7 @@ func TestReadStateDuringFlattening(t *testing.T) { snap := snaps.Snapshot(common.HexToHash("0xa3")) // Register the testing hook to access the state after flattening - var result = make(chan *Account) + var result = make(chan *types.SlimAccount) snaps.onFlatten = func() { // Spin up a thread to read the account from the pre-created // snapshot handler. It's expected to be blocked. diff --git a/core/state/snapshot/utils.go b/core/state/snapshot/utils.go index fa1f216e68..62f073d2e1 100644 --- a/core/state/snapshot/utils.go +++ b/core/state/snapshot/utils.go @@ -23,9 +23,9 @@ 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/ethdb" "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rlp" ) // CheckDanglingStorage iterates the snap storage data, and verifies that all @@ -98,8 +98,8 @@ func CheckJournalAccount(db ethdb.KeyValueStore, hash common.Hash) error { baseRoot := rawdb.ReadSnapshotRoot(db) fmt.Printf("Disklayer: Root: %x\n", baseRoot) if data := rawdb.ReadAccountSnapshot(db, hash); data != nil { - account := new(Account) - if err := rlp.DecodeBytes(data, account); err != nil { + account, err := types.FullAccount(data) + if err != nil { panic(err) } fmt.Printf("\taccount.nonce: %d\n", account.Nonce) @@ -129,8 +129,8 @@ func CheckJournalAccount(db ethdb.KeyValueStore, hash common.Hash) error { } fmt.Printf("Disklayer+%d: Root: %x, parent %x\n", depth, root, pRoot) if data, ok := accounts[hash]; ok { - account := new(Account) - if err := rlp.DecodeBytes(data, account); err != nil { + account, err := types.FullAccount(data) + if err != nil { panic(err) } fmt.Printf("\taccount.nonce: %d\n", account.Nonce) diff --git a/core/state/state_object.go b/core/state/state_object.go index bde64d541f..b9fa2ff103 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -57,29 +57,38 @@ func (s Storage) Copy() Storage { // stateObject represents an Ethereum account which is being modified. // // The usage pattern is as follows: -// First you need to obtain a state object. -// Account values can be accessed and modified through the object. -// Finally, call commitTrie to write the modified storage trie into a database. +// - First you need to obtain a state object. +// - Account values as well as storages can be accessed and modified through the object. +// - Finally, call commit to return the changes of storage trie and update account data. type stateObject struct { - address common.Address - addrHash common.Hash // hash of ethereum address of the account - data types.StateAccount db *StateDB + address common.Address // address of ethereum account + addrHash common.Hash // hash of ethereum address of the account + origin *types.StateAccount // Account original data without any change applied, nil means it was not existent + 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 - originStorage Storage // Storage cache of original entries to dedup rewrites, reset for every transaction + 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 + dirtyStorage Storage // Storage entries that have been modified in the current transaction execution, reset for every transaction // Cache flags. - // When an object is marked suicided it will be deleted from the trie - // during the "update" phase of the state transition. dirtyCode bool // true if the code was updated - suicided bool - deleted bool + + // 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 } // empty returns whether the account is considered empty. @@ -88,21 +97,17 @@ func (s *stateObject) empty() bool { } // newObject creates a state object. -func newObject(db *StateDB, address common.Address, data types.StateAccount) *stateObject { - if data.Balance == nil { - data.Balance = new(big.Int) - } - if data.CodeHash == nil { - data.CodeHash = types.EmptyCodeHash.Bytes() - } - if data.Root == (common.Hash{}) { - data.Root = types.EmptyRootHash +func newObject(db *StateDB, address common.Address, acct *types.StateAccount) *stateObject { + origin := acct + if acct == nil { + acct = types.NewEmptyStateAccount() } return &stateObject{ db: db, address: address, addrHash: crypto.Keccak256Hash(address[:]), - data: data, + origin: origin, + data: *acct, originStorage: make(Storage), pendingStorage: make(Storage), dirtyStorage: make(Storage), @@ -114,8 +119,8 @@ func (s *stateObject) EncodeRLP(w io.Writer) error { return rlp.Encode(w, &s.data) } -func (s *stateObject) markSuicided() { - s.suicided = true +func (s *stateObject) markSelfdestructed() { + s.selfDestructed = true } func (s *stateObject) touch() { @@ -132,17 +137,15 @@ 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. -func (s *stateObject) getTrie(db Database) (Trie, error) { +func (s *stateObject) getTrie() (Trie, error) { if s.trie == nil { // Try fetching from prefetcher first - // We don't prefetch empty tries if s.data.Root != types.EmptyRootHash && s.db.prefetcher != nil { - // When the miner is creating the pending state, there is no - // prefetcher + // 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 := db.OpenStorageTrie(s.db.originalRoot, s.addrHash, s.data.Root) + tr, err := s.db.db.OpenStorageTrie(s.db.originalRoot, s.address, s.data.Root) if err != nil { return nil, err } @@ -153,18 +156,18 @@ func (s *stateObject) getTrie(db Database) (Trie, error) { } // GetState retrieves a value from the account storage trie. -func (s *stateObject) GetState(db Database, key common.Hash) common.Hash { +func (s *stateObject) GetState(key common.Hash) common.Hash { // If we have a dirty value for this state entry, return it value, dirty := s.dirtyStorage[key] if dirty { return value } // Otherwise return the entry's original value - return s.GetCommittedState(db, key) + return s.GetCommittedState(key) } // GetCommittedState retrieves a value from the committed account storage trie. -func (s *stateObject) GetCommittedState(db Database, key common.Hash) common.Hash { +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 { return value @@ -183,8 +186,9 @@ func (s *stateObject) GetCommittedState(db Database, key common.Hash) common.Has } // If no live objects are available, attempt to use snapshots var ( - enc []byte - err error + enc []byte + err error + value common.Hash ) if s.db.snap != nil { start := time.Now() @@ -192,16 +196,23 @@ func (s *stateObject) GetCommittedState(db Database, key common.Hash) common.Has if metrics.EnabledExpensive { 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(db) + tr, err := s.getTrie() if err != nil { s.db.setError(err) return common.Hash{} } - enc, err = tr.GetStorage(s.address, key.Bytes()) + val, err := tr.GetStorage(s.address, key.Bytes()) if metrics.EnabledExpensive { s.db.StorageReads += time.Since(start) } @@ -209,23 +220,16 @@ func (s *stateObject) GetCommittedState(db Database, key common.Hash) common.Has s.db.setError(err) return common.Hash{} } - } - var value common.Hash - if len(enc) > 0 { - _, content, _, err := rlp.Split(enc) - if err != nil { - s.db.setError(err) - } - value.SetBytes(content) + value.SetBytes(val) } s.originStorage[key] = value return value } // SetState updates a value in account storage. -func (s *stateObject) SetState(db Database, key, value common.Hash) { +func (s *stateObject) SetState(key, value common.Hash) { // If the new value is the same as old, don't set - prev := s.GetState(db, key) + prev := s.GetState(key) if prev == value { return } @@ -260,12 +264,17 @@ func (s *stateObject) finalise(prefetch bool) { } } -// updateTrie writes cached storage modifications into the object's storage trie. -// It will return nil if the trie has not been loaded and no changes have been -// made. An error will be returned if the trie can't be loaded/updated correctly. -func (s *stateObject) updateTrie(db Database) (Trie, error) { +// updateTrie is responsible for persisting cached storage changes into the +// object's storage trie. In case the storage trie is not yet loaded, this +// function will load the trie automatically. If any issues arise during the +// 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. +func (s *stateObject) updateTrie() (Trie, error) { // Make sure all dirty slots are finalized into the pending storage area - s.finalise(false) // Don't prefetch anymore, pull directly if need be + s.finalise(false) + + // Short circuit if nothing changed, don't bother with hashing anything if len(s.pendingStorage) == 0 { return s.trie, nil } @@ -276,23 +285,24 @@ func (s *stateObject) updateTrie(db Database) (Trie, error) { // The snapshot storage map for the object var ( storage map[common.Hash][]byte - hasher = s.db.hasher + origin map[common.Hash][]byte ) - tr, err := s.getTrie(db) + tr, err := s.getTrie() if err != nil { s.db.setError(err) return nil, err } - // Insert all the pending updates into the trie + // Insert all the pending storage updates into the trie usedStorage := make([][]byte, 0, len(s.pendingStorage)) for key, value := range s.pendingStorage { // Skip noop changes, persist actual changes if value == s.originStorage[key] { continue } + prev := s.originStorage[key] s.originStorage[key] = value - var v []byte + 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) @@ -301,44 +311,58 @@ func (s *stateObject) updateTrie(db Database) (Trie, error) { s.db.StorageDeleted += 1 } else { // Encoding []byte cannot fail, ok to ignore the error. - v, _ = rlp.EncodeToBytes(common.TrimLeftZeroes(value[:])) - if err := tr.UpdateStorage(s.address, key[:], v); err != nil { + trimmed := common.TrimLeftZeroes(value[:]) + encoded, _ = rlp.EncodeToBytes(trimmed) + if err := tr.UpdateStorage(s.address, key[:], trimmed); err != nil { s.db.setError(err) return nil, err } s.db.StorageUpdated += 1 } - // If state snapshotting is active, cache the data til commit - if s.db.snap != nil { - if storage == nil { - // Retrieve the old storage map, if available, create a new one otherwise - if storage = s.db.snapStorage[s.addrHash]; storage == nil { - storage = make(map[common.Hash][]byte) - s.db.snapStorage[s.addrHash] = storage - } + // Cache the mutated storage slots until commit + if storage == nil { + if storage = s.db.storages[s.addrHash]; storage == nil { + storage = make(map[common.Hash][]byte) + s.db.storages[s.addrHash] = storage } - storage[crypto.HashData(hasher, key[:])] = v // v will be nil if it's deleted } + khash := crypto.HashData(s.db.hasher, key[:]) + storage[khash] = encoded // encoded will be nil if it's deleted + + // Cache the original value of mutated storage slots + if origin == nil { + if origin = s.db.storagesOrigin[s.address]; origin == nil { + origin = make(map[common.Hash][]byte) + s.db.storagesOrigin[s.address] = origin + } + } + // 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 } if s.db.prefetcher != nil { s.db.prefetcher.used(s.addrHash, s.data.Root, usedStorage) } - if len(s.pendingStorage) > 0 { - s.pendingStorage = make(Storage) - } + s.pendingStorage = make(Storage) // reset pending map return tr, nil } -// UpdateRoot sets the trie root to the current root hash of. An error -// will be returned if trie root hash is not computed correctly. -func (s *stateObject) updateRoot(db Database) { - tr, err := s.updateTrie(db) - if err != nil { - return - } - // If nothing changed, don't bother with hashing anything - if tr == nil { +// updateRoot flushes all cached storage mutations to trie, recalculating the +// 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. + tr, err := s.updateTrie() + if err != nil || tr == nil { return } // Track the amount of time wasted on hashing the storage trie @@ -348,23 +372,30 @@ func (s *stateObject) updateRoot(db Database) { s.data.Root = tr.Hash() } -// commitTrie submits the storage changes into the storage trie and re-computes -// the root. Besides, all trie changes will be collected in a nodeset and returned. -func (s *stateObject) commitTrie(db Database) (*trienode.NodeSet, error) { - tr, err := s.updateTrie(db) - if err != nil { - return nil, err - } - // If nothing changed, don't bother with committing anything - if tr == nil { +// 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. +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 { + s.origin = s.data.Copy() 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()) } - root, nodes := tr.Commit(false) + // 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 + } s.data.Root = root + + // Update original account data after commit + s.origin = s.data.Copy() return nodes, nil } @@ -404,18 +435,24 @@ func (s *stateObject) setBalance(amount *big.Int) { } func (s *stateObject) deepCopy(db *StateDB) *stateObject { - stateObject := newObject(db, s.address, s.data) - if s.trie != nil { - stateObject.trie = db.db.CopyTrie(s.trie) + obj := &stateObject{ + db: db, + address: s.address, + addrHash: s.addrHash, + origin: s.origin, + data: s.data, } - stateObject.code = s.code - stateObject.dirtyStorage = s.dirtyStorage.Copy() - stateObject.originStorage = s.originStorage.Copy() - stateObject.pendingStorage = s.pendingStorage.Copy() - stateObject.suicided = s.suicided - stateObject.dirtyCode = s.dirtyCode - stateObject.deleted = s.deleted - return stateObject + if s.trie != nil { + 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.dirtyCode = s.dirtyCode + obj.deleted = s.deleted + return obj } // clearStorageCache clears the various storage caches @@ -437,14 +474,14 @@ func (s *stateObject) Address() common.Address { } // Code returns the contract code associated with this object, if any. -func (s *stateObject) Code(db Database) []byte { +func (s *stateObject) Code() []byte { if s.code != nil { return s.code } if bytes.Equal(s.CodeHash(), types.EmptyCodeHash.Bytes()) { return nil } - code, err := db.ContractCode(s.addrHash, common.BytesToHash(s.CodeHash())) + code, err := s.db.db.ContractCode(s.address, common.BytesToHash(s.CodeHash())) if err != nil { s.db.setError(fmt.Errorf("can't load code hash %x: %v", s.CodeHash(), err)) } @@ -455,14 +492,14 @@ func (s *stateObject) Code(db Database) []byte { // CodeSize returns the size of the contract code associated with this object, // 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(db Database) int { +func (s *stateObject) CodeSize() int { if s.code != nil { return len(s.code) } if bytes.Equal(s.CodeHash(), types.EmptyCodeHash.Bytes()) { return 0 } - size, err := db.ContractCodeSize(s.addrHash, common.BytesToHash(s.CodeHash())) + size, err := s.db.db.ContractCodeSize(s.address, common.BytesToHash(s.CodeHash())) if err != nil { s.db.setError(fmt.Errorf("can't load code size %x: %v", s.CodeHash(), err)) } @@ -470,7 +507,7 @@ func (s *stateObject) CodeSize(db Database) int { } func (s *stateObject) SetCode(codeHash common.Hash, code []byte) { - prevcode := s.Code(s.db.db) + prevcode := s.Code() s.db.journal.append(codeChange{ account: &s.address, prevhash: s.CodeHash(), @@ -508,3 +545,7 @@ func (s *stateObject) Balance() *big.Int { func (s *stateObject) Nonce() uint64 { return s.data.Nonce } + +func (s *stateObject) Root() common.Hash { + return s.data.Root +} diff --git a/core/state/state_test.go b/core/state/state_test.go index ada1e801ee..2553133dea 100644 --- a/core/state/state_test.go +++ b/core/state/state_test.go @@ -18,6 +18,7 @@ package state import ( "bytes" + "encoding/json" "math/big" "testing" @@ -29,21 +30,22 @@ import ( "github.com/ethereum/go-ethereum/trie" ) -type stateTest struct { +type stateEnv struct { db ethdb.Database state *StateDB } -func newStateTest() *stateTest { +func newStateEnv() *stateEnv { db := rawdb.NewMemoryDatabase() sdb, _ := New(types.EmptyRootHash, NewDatabase(db), nil) - return &stateTest{db: db, state: sdb} + return &stateEnv{db: db, state: sdb} } func TestDump(t *testing.T) { db := rawdb.NewMemoryDatabase() - sdb, _ := New(types.EmptyRootHash, NewDatabaseWithConfig(db, &trie.Config{Preimages: true}), nil) - s := &stateTest{db: db, state: sdb} + tdb := NewDatabaseWithConfig(db, &trie.Config{Preimages: true}) + sdb, _ := New(types.EmptyRootHash, tdb, nil) + s := &stateEnv{db: db, state: sdb} // generate a few entries obj1 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x01})) @@ -56,9 +58,10 @@ func TestDump(t *testing.T) { // write some of them to the trie s.state.updateStateObject(obj1) s.state.updateStateObject(obj2) - s.state.Commit(false) + root, _ := s.state.Commit(0, false) // check that DumpToCollector contains the state objects that are in trie + s.state, _ = New(root, tdb, nil) got := string(s.state.Dump(nil)) want := `{ "root": "71edff0130dd2385947095001c73d9e28d862fc286fca2b922ca6f6f3cddfdd2", @@ -92,15 +95,52 @@ func TestDump(t *testing.T) { } } +func TestIterativeDump(t *testing.T) { + db := rawdb.NewMemoryDatabase() + tdb := NewDatabaseWithConfig(db, &trie.Config{Preimages: true}) + sdb, _ := New(types.EmptyRootHash, tdb, nil) + s := &stateEnv{db: db, state: sdb} + + // generate a few entries + obj1 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x01})) + obj1.AddBalance(big.NewInt(22)) + 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(big.NewInt(44)) + obj4 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x00})) + obj4.AddBalance(big.NewInt(1337)) + + // write some of them to the trie + s.state.updateStateObject(obj1) + s.state.updateStateObject(obj2) + root, _ := s.state.Commit(0, false) + s.state, _ = New(root, tdb, nil) + + b := &bytes.Buffer{} + s.state.IterativeDump(nil, json.NewEncoder(b)) + // check that DumpToCollector contains the state objects that are in trie + got := b.String() + want := `{"root":"0xd5710ea8166b7b04bc2bfb129d7db12931cee82f75ca8e2d075b4884322bf3de"} +{"balance":"22","nonce":0,"root":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","codeHash":"0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470","address":"0x0000000000000000000000000000000000000001","key":"0x1468288056310c82aa4c01a7e12a10f8111a0560e72b700555479031b86c357d"} +{"balance":"1337","nonce":0,"root":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","codeHash":"0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470","address":"0x0000000000000000000000000000000000000000","key":"0x5380c7b7ae81a58eb98d9c78de4a1fd7fd9535fc953ed2be602daaa41767312a"} +{"balance":"0","nonce":0,"root":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","codeHash":"0x87874902497a5bb968da31a2998d8f22e949d1ef6214bcdedd8bae24cca4b9e3","code":"0x03030303030303","address":"0x0000000000000000000000000000000000000102","key":"0xa17eacbc25cda025e81db9c5c62868822c73ce097cee2a63e33a2e41268358a1"} +{"balance":"44","nonce":0,"root":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","codeHash":"0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470","address":"0x0000000000000000000000000000000000000002","key":"0xd52688a8f926c816ca1e079067caba944f158e764817b83fc43594370ca9cf62"} +` + if got != want { + t.Errorf("DumpToCollector mismatch:\ngot: %s\nwant: %s\n", got, want) + } +} + func TestNull(t *testing.T) { - s := newStateTest() + s := newStateEnv() address := common.HexToAddress("0x823140710bf13990e4500136726d8b55") s.state.CreateAccount(address) //value := common.FromHex("0x823140710bf13990e4500136726d8b55") var value common.Hash s.state.SetState(address, common.Hash{}, value) - s.state.Commit(false) + s.state.Commit(0, false) if value := s.state.GetState(address, common.Hash{}); value != (common.Hash{}) { t.Errorf("expected empty current value, got %x", value) @@ -115,7 +155,7 @@ func TestSnapshot(t *testing.T) { var storageaddr common.Hash data1 := common.BytesToHash([]byte{42}) data2 := common.BytesToHash([]byte{43}) - s := newStateTest() + s := newStateEnv() // snapshot the genesis state genesis := s.state.Snapshot() @@ -146,7 +186,7 @@ func TestSnapshot(t *testing.T) { } func TestSnapshotEmpty(t *testing.T) { - s := newStateTest() + s := newStateEnv() s.state.RevertToSnapshot(s.state.Snapshot()) } @@ -168,11 +208,11 @@ func TestSnapshot2(t *testing.T) { so0.SetBalance(big.NewInt(42)) so0.SetNonce(43) so0.SetCode(crypto.Keccak256Hash([]byte{'c', 'a', 'f', 'e'}), []byte{'c', 'a', 'f', 'e'}) - so0.suicided = false + so0.selfDestructed = false so0.deleted = false state.setStateObject(so0) - root, _ := state.Commit(false) + root, _ := state.Commit(0, false) state, _ = New(root, state.db, state.snaps) // and one with deleted == true @@ -180,7 +220,7 @@ func TestSnapshot2(t *testing.T) { so1.SetBalance(big.NewInt(52)) so1.SetNonce(53) so1.SetCode(crypto.Keccak256Hash([]byte{'c', 'a', 'f', 'e', '2'}), []byte{'c', 'a', 'f', 'e', '2'}) - so1.suicided = true + so1.selfDestructed = true so1.deleted = true state.setStateObject(so1) @@ -194,8 +234,8 @@ func TestSnapshot2(t *testing.T) { so0Restored := state.getStateObject(stateobjaddr0) // Update lazily-loaded values before comparing. - so0Restored.GetState(state.db, storageaddr) - so0Restored.Code(state.db) + so0Restored.GetState(storageaddr) + so0Restored.Code() // non-deleted is equal (restored) compareStateObjects(so0Restored, so0, t) diff --git a/core/state/statedb.go b/core/state/statedb.go index 777fc17d13..9e58f01455 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -18,7 +18,6 @@ package state import ( - "errors" "fmt" "math/big" "sort" @@ -32,9 +31,15 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/params" - "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" +) + +const ( + // storageDeleteLimit denotes the highest permissible memory allocation + // employed for contract storage deletion. + storageDeleteLimit = 512 * 1024 * 1024 ) type revision struct { @@ -42,42 +47,42 @@ type revision struct { journalIndex int } -type proofList [][]byte - -func (n *proofList) Put(key []byte, value []byte) error { - *n = append(*n, value) - return nil -} - -func (n *proofList) Delete(key []byte) error { - panic("not supported") -} - // 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: +// // * Contracts // * Accounts +// +// 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. type StateDB struct { db Database prefetcher *triePrefetcher trie Trie hasher crypto.KeccakState + snaps *snapshot.Tree // Nil if snapshot is not available + snap snapshot.Snapshot // Nil if snapshot is not available // originalRoot is the pre-state root, before any changes were made. // It will be updated when the Commit is called. originalRoot common.Hash - snaps *snapshot.Tree - snap snapshot.Snapshot - snapAccounts map[common.Hash][]byte - snapStorage map[common.Hash]map[common.Hash][]byte + // 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 + 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 - // This map holds 'live' objects, which will get modified while processing a state transition. + // 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]struct{} // State objects destructed in the block + 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 // DB error. // State objects are used by the consensus core and VM which are @@ -91,11 +96,13 @@ type StateDB struct { // The refund counter, also used by state transitioning. refund uint64 + // The tx context and all occurred logs in the scope of transaction. thash common.Hash txIndex int logs map[common.Hash][]*types.Log logSize uint + // Preimages occurred seen by VM in the scope of block. preimages map[common.Hash][]byte // Per-transaction access list @@ -128,6 +135,9 @@ type StateDB struct { StorageUpdated int AccountDeleted int StorageDeleted int + + // Testing hooks + onCommit func(states *triestate.Set) // Hook invoked when commit is performed } // New creates a new state from a given trie. @@ -141,10 +151,14 @@ 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), stateObjectsPending: make(map[common.Address]struct{}), stateObjectsDirty: make(map[common.Address]struct{}), - stateObjectsDestruct: make(map[common.Address]struct{}), + stateObjectsDestruct: make(map[common.Address]*types.StateAccount), logs: make(map[common.Hash][]*types.Log), preimages: make(map[common.Hash][]byte), journal: newJournal(), @@ -153,10 +167,7 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error) hasher: crypto.NewKeccakState(), } if sdb.snaps != nil { - if sdb.snap = sdb.snaps.Snapshot(root); sdb.snap != nil { - sdb.snapAccounts = make(map[common.Hash][]byte) - sdb.snapStorage = make(map[common.Hash]map[common.Hash][]byte) - } + sdb.snap = sdb.snaps.Snapshot(root) } return sdb, nil } @@ -256,7 +267,7 @@ func (s *StateDB) SubRefund(gas uint64) { } // Exist reports whether the given account address exists in the state. -// Notably this also returns true for suicided accounts. +// Notably this also returns true for self-destructed accounts. func (s *StateDB) Exist(addr common.Address) bool { return s.getStateObject(addr) != nil } @@ -277,6 +288,7 @@ func (s *StateDB) GetBalance(addr common.Address) *big.Int { return common.Big0 } +// GetNonce retrieves the nonce from the given address or 0 if object not found func (s *StateDB) GetNonce(addr common.Address) uint64 { stateObject := s.getStateObject(addr) if stateObject != nil { @@ -286,6 +298,16 @@ func (s *StateDB) GetNonce(addr common.Address) uint64 { return 0 } +// GetStorageRoot retrieves the storage root from the given address or empty +// if object not found. +func (s *StateDB) GetStorageRoot(addr common.Address) common.Hash { + stateObject := s.getStateObject(addr) + if stateObject != nil { + return stateObject.Root() + } + return common.Hash{} +} + // TxIndex returns the current transaction index set by Prepare. func (s *StateDB) TxIndex() int { return s.txIndex @@ -294,7 +316,7 @@ func (s *StateDB) TxIndex() int { func (s *StateDB) GetCode(addr common.Address) []byte { stateObject := s.getStateObject(addr) if stateObject != nil { - return stateObject.Code(s.db) + return stateObject.Code() } return nil } @@ -302,7 +324,7 @@ func (s *StateDB) GetCode(addr common.Address) []byte { func (s *StateDB) GetCodeSize(addr common.Address) int { stateObject := s.getStateObject(addr) if stateObject != nil { - return stateObject.CodeSize(s.db) + return stateObject.CodeSize() } return 0 } @@ -319,45 +341,16 @@ func (s *StateDB) GetCodeHash(addr common.Address) common.Hash { func (s *StateDB) GetState(addr common.Address, hash common.Hash) common.Hash { stateObject := s.getStateObject(addr) if stateObject != nil { - return stateObject.GetState(s.db, hash) + return stateObject.GetState(hash) } return common.Hash{} } -// GetProof returns the Merkle proof for a given account. -func (s *StateDB) GetProof(addr common.Address) ([][]byte, error) { - return s.GetProofByHash(crypto.Keccak256Hash(addr.Bytes())) -} - -// GetProofByHash returns the Merkle proof for a given account. -func (s *StateDB) GetProofByHash(addrHash common.Hash) ([][]byte, error) { - var proof proofList - err := s.trie.Prove(addrHash[:], 0, &proof) - return proof, err -} - -// GetStorageProof returns the Merkle proof for given storage slot. -func (s *StateDB) GetStorageProof(a common.Address, key common.Hash) ([][]byte, error) { - trie, err := s.StorageTrie(a) - if err != nil { - return nil, err - } - if trie == nil { - return nil, errors.New("storage trie for requested address does not exist") - } - var proof proofList - err = trie.Prove(crypto.Keccak256(key.Bytes()), 0, &proof) - if err != nil { - return nil, err - } - return proof, nil -} - // GetCommittedState retrieves a value from the given account's committed storage trie. func (s *StateDB) GetCommittedState(addr common.Address, hash common.Hash) common.Hash { stateObject := s.getStateObject(addr) if stateObject != nil { - return stateObject.GetCommittedState(s.db, hash) + return stateObject.GetCommittedState(hash) } return common.Hash{} } @@ -367,25 +360,10 @@ func (s *StateDB) Database() Database { return s.db } -// StorageTrie returns the storage trie of an account. The return value is a copy -// and is nil for non-existent accounts. An error will be returned if storage trie -// is existent but can't be loaded correctly. -func (s *StateDB) StorageTrie(addr common.Address) (Trie, error) { - stateObject := s.getStateObject(addr) - if stateObject == nil { - return nil, nil - } - cpy := stateObject.deepCopy(s) - if _, err := cpy.updateTrie(s.db); err != nil { - return nil, err - } - return cpy.getTrie(s.db) -} - -func (s *StateDB) HasSuicided(addr common.Address) bool { +func (s *StateDB) HasSelfDestructed(addr common.Address) bool { stateObject := s.getStateObject(addr) if stateObject != nil { - return stateObject.suicided + return stateObject.selfDestructed } return false } @@ -434,47 +412,62 @@ func (s *StateDB) SetCode(addr common.Address, code []byte) { func (s *StateDB) SetState(addr common.Address, key, value common.Hash) { stateObject := s.GetOrNewStateObject(addr) if stateObject != nil { - stateObject.SetState(s.db, key, value) + stateObject.SetState(key, value) } } // SetStorage replaces the entire storage for the specified account with given -// storage. This function should only be used for debugging. +// 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 // to a previous incarnation of the object. - s.stateObjectsDestruct[addr] = struct{}{} + // + // 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 + } stateObject := s.GetOrNewStateObject(addr) // If object was already in memory, it might have cached // storage slots. These should be cleared. stateObject.clearStorageCache() for k, v := range storage { - stateObject.SetState(s.db, k, v) + stateObject.SetState(k, v) } } -// Suicide marks the given account as suicided. +// SelfDestruct marks the given account as selfdestructed. // This clears the account balance. // // The account's state object is still available until the state is committed, -// getStateObject will return a non-nil account after Suicide. -func (s *StateDB) Suicide(addr common.Address) bool { +// getStateObject will return a non-nil account after SelfDestruct. +func (s *StateDB) SelfDestruct(addr common.Address) { stateObject := s.getStateObject(addr) if stateObject == nil { - return false + return } - s.journal.append(suicideChange{ + s.journal.append(selfDestructChange{ account: &addr, - prev: stateObject.suicided, + prev: stateObject.selfDestructed, prevbalance: new(big.Int).Set(stateObject.Balance()), }) - stateObject.markSuicided() + stateObject.markSelfdestructed() stateObject.data.Balance = new(big.Int) +} - return true +func (s *StateDB) Selfdestruct6780(addr common.Address) { + stateObject := s.getStateObject(addr) + if stateObject == nil { + return + } + + if stateObject.created { + s.SelfDestruct(addr) + } } // SetTransientState sets transient storage for a given account. It @@ -519,13 +512,24 @@ func (s *StateDB) updateStateObject(obj *stateObject) { if err := s.trie.UpdateAccount(addr, &obj.data); err != nil { s.setError(fmt.Errorf("updateStateObject (%x) error: %v", addr[:], err)) } + 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) - // If state snapshotting is active, cache the data til 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. - if s.snap != nil { - s.snapAccounts[obj.addrHash] = snapshot.SlimAccountRLP(obj.data.Nonce, obj.data.Balance, obj.data.Root, obj.data.CodeHash) + // 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) + } } } @@ -604,7 +608,7 @@ func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject { } } // Insert into the live set - obj := newObject(s, addr, *data) + obj := newObject(s, addr, data) s.setStateObject(obj) return obj } @@ -626,20 +630,40 @@ func (s *StateDB) GetOrNewStateObject(addr common.Address) *stateObject { // 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! - - var prevdestruct bool - if prev != nil { - _, prevdestruct = s.stateObjectsDestruct[prev.address] - if !prevdestruct { - s.stateObjectsDestruct[prev.address] = struct{}{} - } - } - newobj = newObject(s, addr, types.StateAccount{}) + newobj = newObject(s, addr, nil) if prev == nil { s.journal.append(createObjectChange{account: &addr}) } else { - s.journal.append(resetObjectChange{prev: prev, prevdestruct: prevdestruct}) + // 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) } + + newobj.created = true + s.setStateObject(newobj) if prev != nil && !prev.deleted { return newobj, prev @@ -664,39 +688,6 @@ func (s *StateDB) CreateAccount(addr common.Address) { } } -func (db *StateDB) ForEachStorage(addr common.Address, cb func(key, value common.Hash) bool) error { - so := db.getStateObject(addr) - if so == nil { - return nil - } - tr, err := so.getTrie(db.db) - if err != nil { - return err - } - it := trie.NewIterator(tr.NodeIterator(nil)) - - for it.Next() { - key := common.BytesToHash(db.trie.GetKey(it.Key)) - if value, dirty := so.dirtyStorage[key]; dirty { - if !cb(key, value) { - return nil - } - continue - } - - if len(it.Value) > 0 { - _, content, _, err := rlp.Split(it.Value) - if err != nil { - return err - } - if !cb(key, common.BytesToHash(content)) { - return nil - } - } - } - return nil -} - // Copy creates a deep, independent copy of the state. // Snapshots of the copied state cannot be applied to the copy. func (s *StateDB) Copy() *StateDB { @@ -705,16 +696,27 @@ 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), 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]struct{}, len(s.stateObjectsDestruct)), + stateObjectsDestruct: make(map[common.Address]*types.StateAccount, len(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)), journal: newJournal(), hasher: crypto.NewKeccakState(), + + // 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, } // Copy the dirty states, logs, and preimages for addr := range s.journal.dirties { @@ -748,10 +750,18 @@ func (s *StateDB) Copy() *StateDB { } state.stateObjectsDirty[addr] = struct{}{} } - // Deep copy the destruction flag. - for addr := range s.stateObjectsDestruct { - state.stateObjectsDestruct[addr] = struct{}{} + // Deep copy the destruction markers. + for addr, value := range s.stateObjectsDestruct { + state.stateObjectsDestruct[addr] = value } + // 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 { cpy := make([]*types.Log, len(logs)) for i, l := range logs { @@ -760,6 +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 } @@ -778,28 +789,6 @@ func (s *StateDB) Copy() *StateDB { if s.prefetcher != nil { state.prefetcher = s.prefetcher.copy() } - if s.snaps != nil { - // In order for the miner 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 - state.snaps = s.snaps - state.snap = s.snap - - // deep copy needed - state.snapAccounts = make(map[common.Hash][]byte, len(s.snapAccounts)) - for k, v := range s.snapAccounts { - state.snapAccounts[k] = v - } - state.snapStorage = make(map[common.Hash]map[common.Hash][]byte, len(s.snapStorage)) - for k, v := range s.snapStorage { - temp := make(map[common.Hash][]byte, len(v)) - for kk, vv := range v { - temp[kk] = vv - } - state.snapStorage[k] = temp - } - } return state } @@ -848,24 +837,26 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) { // Thus, we can safely ignore it here continue } - if obj.suicided || (deleteEmptyObjects && obj.empty()) { + if obj.selfDestructed || (deleteEmptyObjects && obj.empty()) { obj.deleted = true // We need to maintain account deletions explicitly (will remain - // set indefinitely). - s.stateObjectsDestruct[obj.address] = struct{}{} - - // If state snapshotting is active, also mark the destruction there. + // 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 + } // 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. - if s.snap != nil { - delete(s.snapAccounts, obj.addrHash) // Clear out any previously updated account data (may be recreated via a resurrect) - delete(s.snapStorage, obj.addrHash) // Clear out any previously updated storage data (may be recreated via a resurrect) - } + 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(true) // Prefetch slots in the background } + obj.created = false s.stateObjectsPending[addr] = struct{}{} s.stateObjectsDirty[addr] = struct{}{} @@ -909,7 +900,7 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { // to pull useful data from disk. for addr := range s.stateObjectsPending { if obj := s.stateObjects[addr]; !obj.deleted { - obj.updateRoot(s.db) + obj.updateRoot() } } // Now we're about to start to write changes to the trie. The trie is so far @@ -960,8 +951,223 @@ func (s *StateDB) clearJournalAndRefund() { s.validRevisions = s.validRevisions[:0] // Snapshots can be created without journal entries } +// fastDeleteStorage is the function that efficiently deletes the storage trie +// 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) { + iter, err := s.snaps.StorageIterator(s.originalRoot, addrHash, common.Hash{}) + if err != nil { + return false, 0, nil, nil, err + } + defer iter.Release() + + var ( + size common.StorageSize + nodes = trienode.NewNodeSet(addrHash) + slots = make(map[common.Hash][]byte) + ) + stack := trie.NewStackTrie(func(owner common.Hash, path []byte, hash common.Hash, blob []byte) { + nodes.AddNode(path, trienode.NewDeleted()) + size += common.StorageSize(len(path)) + }) + for iter.Next() { + if size > storageDeleteLimit { + return true, size, nil, nil, nil + } + slot := common.CopyBytes(iter.Slot()) + if iter.Error() != nil { // error might occur after Slot function + return false, 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 + } + } + if iter.Error() != nil { // error might occur during iteration + return false, 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 false, 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) { + tr, err := s.db.OpenStorageTrie(s.originalRoot, addr, root) + if err != nil { + return false, 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) + } + var ( + size common.StorageSize + nodes = trienode.NewNodeSet(addrHash) + 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())) + 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 false, 0, nil, nil, err + } + return false, size, slots, nodes, nil +} + +// 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. +func (s *StateDB) deleteStorage(addr common.Address, addrHash common.Hash, root common.Hash) (bool, 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 + ) + // 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) + } + if s.snap == nil || err != nil { + aborted, size, slots, nodes, err = s.slowDeleteStorage(addr, addrHash, root) + } + if err != nil { + return false, nil, nil, err + } + if metrics.EnabledExpensive { + if aborted { + slotDeletionSkip.Inc(1) + } + n := int64(len(slots)) + if n > slotDeletionMaxCount.Value() { + slotDeletionMaxCount.Update(n) + } + if int64(size) > slotDeletionMaxSize.Value() { + slotDeletionMaxSize.Update(int64(size)) + } + slotDeletionTimer.UpdateSince(start) + slotDeletionCount.Mark(n) + slotDeletionSize.Mark(int64(size)) + } + return aborted, slots, nodes, nil +} + +// 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. +// +// - 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. +// +// 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) (map[common.Address]struct{}, 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 + } + 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[:]) + 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) + + // Short circuit if the storage was empty. + if prev.Root == types.EmptyRootHash { + continue + } + // Remove storage slots belong to the account. + aborted, 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 + } + 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 nil, err + } + } + return incomplete, nil +} + // Commit writes the state to the underlying in-memory trie database. -func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { +// 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) { // 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) @@ -978,37 +1184,38 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { nodes = trienode.NewMergedNodeSet() codeWriter = s.db.DiskDB().NewBatch() ) + // Handle all state deletions first + incomplete, err := s.handleDestruction(nodes) + if err != nil { + return common.Hash{}, err + } + // Handle all state updates afterwards for addr := range s.stateObjectsDirty { - if obj := s.stateObjects[addr]; !obj.deleted { - // Write any contract code associated with the state object - if obj.code != nil && obj.dirtyCode { - rawdb.WriteCode(codeWriter, common.BytesToHash(obj.CodeHash()), obj.code) - obj.dirtyCode = false - } - // Write any storage changes in the state object to its storage trie - set, err := obj.commitTrie(s.db) - if err != nil { + obj := s.stateObjects[addr] + if obj.deleted { + continue + } + // Write any contract code associated with the state object + if obj.code != nil && obj.dirtyCode { + rawdb.WriteCode(codeWriter, 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 } - // Merge the dirty nodes of storage trie into global set. - if set != nil { - if err := nodes.Merge(set); err != nil { - return common.Hash{}, err - } - updates, deleted := set.Size() - storageTrieNodesUpdated += updates - storageTrieNodesDeleted += deleted - } + updates, deleted := set.Size() + storageTrieNodesUpdated += updates + storageTrieNodesDeleted += deleted } - // If the contract is destructed, the storage is still left in the - // database as dangling data. Theoretically it's should be wiped from - // database as well, but in hash-based-scheme it's extremely hard to - // determine that if the trie nodes are also referenced by other storage, - // and in path-based-scheme some technical challenges are still unsolved. - // Although it won't affect the correctness but please fix it TODO(rjl493456442). - } - if len(s.stateObjectsDirty) > 0 { - s.stateObjectsDirty = make(map[common.Address]struct{}) } if codeWriter.ValueSize() > 0 { if err := codeWriter.Write(); err != nil { @@ -1020,7 +1227,10 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { if metrics.EnabledExpensive { start = time.Now() } - root, set := s.trie.Commit(true) + root, set, err := s.trie.Commit(true) + if 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 { @@ -1047,7 +1257,7 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { 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.snapAccounts, s.snapStorage); err != nil { + 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. @@ -1061,10 +1271,7 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { if metrics.EnabledExpensive { s.SnapshotCommits += time.Since(start) } - s.snap, s.snapAccounts, s.snapStorage = nil, nil, nil - } - if len(s.stateObjectsDestruct) > 0 { - s.stateObjectsDestruct = make(map[common.Address]struct{}) + s.snap = nil } if root == (common.Hash{}) { root = types.EmptyRootHash @@ -1075,14 +1282,25 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { } if root != origin { start := time.Now() - if err := s.db.TrieDB().Update(root, origin, nodes); err != nil { + set := triestate.New(s.accountsOrigin, s.storagesOrigin, incomplete) + 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) } + if s.onCommit != nil { + s.onCommit(set) + } } + // 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.stateObjectsDirty = make(map[common.Address]struct{}) + s.stateObjectsDestruct = make(map[common.Address]*types.StateAccount) return root, nil } @@ -1163,7 +1381,7 @@ func (s *StateDB) SlotInAccessList(addr common.Address, slot common.Hash) (addre } // convertAccountSet converts a provided account set from address keyed to hash keyed. -func (s *StateDB) convertAccountSet(set map[common.Address]struct{}) map[common.Hash]struct{} { +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] @@ -1175,3 +1393,24 @@ func (s *StateDB) convertAccountSet(set map[common.Address]struct{}) map[common. } 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 +} diff --git a/core/state/statedb_fuzz_test.go b/core/state/statedb_fuzz_test.go new file mode 100644 index 0000000000..c4704257c7 --- /dev/null +++ b/core/state/statedb_fuzz_test.go @@ -0,0 +1,392 @@ +// 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 state + +import ( + "bytes" + "encoding/binary" + "errors" + "fmt" + "math" + "math/big" + "math/rand" + "reflect" + "strings" + "testing" + "testing/quick" + + "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/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/triedb/pathdb" + "github.com/ethereum/go-ethereum/trie/triestate" +) + +// A stateTest checks that the state changes are correctly captured. Instances +// of this test with pseudorandom content are created by Generate. +// +// The test works as follows: +// +// A list of states are created by applying actions. The state changes between +// each state instance are tracked and be verified. +type stateTest struct { + addrs []common.Address // all account addresses + actions [][]testAction // modifications to the state, grouped by block + chunk int // The number of actions per chunk + err error // failure details are reported through this field +} + +// newStateTestAction creates a random action that changes state. +func newStateTestAction(addr common.Address, r *rand.Rand, index int) testAction { + actions := []testAction{ + { + name: "SetBalance", + fn: func(a testAction, s *StateDB) { + s.SetBalance(addr, big.NewInt(a.args[0])) + }, + args: make([]int64, 1), + }, + { + name: "SetNonce", + fn: func(a testAction, s *StateDB) { + s.SetNonce(addr, uint64(a.args[0])) + }, + args: make([]int64, 1), + }, + { + name: "SetState", + fn: func(a testAction, s *StateDB) { + var key, val common.Hash + binary.BigEndian.PutUint16(key[:], uint16(a.args[0])) + binary.BigEndian.PutUint16(val[:], uint16(a.args[1])) + s.SetState(addr, key, val) + }, + args: make([]int64, 2), + }, + { + name: "SetCode", + fn: func(a testAction, s *StateDB) { + code := make([]byte, 16) + binary.BigEndian.PutUint64(code, uint64(a.args[0])) + binary.BigEndian.PutUint64(code[8:], uint64(a.args[1])) + s.SetCode(addr, code) + }, + args: make([]int64, 2), + }, + { + name: "CreateAccount", + fn: func(a testAction, s *StateDB) { + s.CreateAccount(addr) + }, + }, + { + name: "Selfdestruct", + fn: func(a testAction, s *StateDB) { + s.SelfDestruct(addr) + }, + }, + } + var nonRandom = index != -1 + if index == -1 { + index = r.Intn(len(actions)) + } + action := actions[index] + var names []string + if !action.noAddr { + names = append(names, addr.Hex()) + } + for i := range action.args { + if nonRandom { + action.args[i] = rand.Int63n(10000) + 1 // set balance to non-zero + } else { + action.args[i] = rand.Int63n(10000) + } + names = append(names, fmt.Sprint(action.args[i])) + } + action.name += " " + strings.Join(names, ", ") + return action +} + +// Generate returns a new snapshot test of the given size. All randomness is +// derived from r. +func (*stateTest) Generate(r *rand.Rand, size int) reflect.Value { + addrs := make([]common.Address, 5) + for i := range addrs { + addrs[i][0] = byte(i) + } + actions := make([][]testAction, rand.Intn(5)+1) + + for i := 0; i < len(actions); i++ { + actions[i] = make([]testAction, size) + for j := range actions[i] { + if j == 0 { + // Always include a set balance action to make sure + // the state changes are not empty. + actions[i][j] = newStateTestAction(common.HexToAddress("0xdeadbeef"), r, 0) + continue + } + actions[i][j] = newStateTestAction(addrs[r.Intn(len(addrs))], r, -1) + } + } + chunk := int(math.Sqrt(float64(size))) + if size > 0 && chunk == 0 { + chunk = 1 + } + return reflect.ValueOf(&stateTest{ + addrs: addrs, + actions: actions, + chunk: chunk, + }) +} + +func (test *stateTest) String() string { + out := new(bytes.Buffer) + for i, actions := range test.actions { + fmt.Fprintf(out, "---- block %d ----\n", i) + for j, action := range actions { + if j%test.chunk == 0 { + fmt.Fprintf(out, "---- transaction %d ----\n", j/test.chunk) + } + fmt.Fprintf(out, "%4d: %s\n", j%test.chunk, action.name) + } + } + return out.String() +} + +func (test *stateTest) run() bool { + var ( + 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)) + } + disk = rawdb.NewMemoryDatabase() + tdb = trie.NewDatabase(disk, &trie.Config{PathDB: pathdb.Defaults}) + sdb = NewDatabaseWithNodeDB(disk, tdb) + byzantium = rand.Intn(2) == 0 + ) + defer disk.Close() + defer tdb.Close() + + var snaps *snapshot.Tree + if rand.Intn(3) == 0 { + snaps, _ = snapshot.New(snapshot.Config{ + CacheSize: 1, + Recovery: false, + NoBuild: false, + AsyncBuild: false, + }, disk, tdb, types.EmptyRootHash) + } + for i, actions := range test.actions { + root := types.EmptyRootHash + if i != 0 { + root = roots[len(roots)-1] + } + state, err := New(root, sdb, snaps) + if err != nil { + panic(err) + } + state.onCommit = onCommit + + for i, action := range actions { + if i%test.chunk == 0 && i != 0 { + if byzantium { + state.Finalise(true) // call finalise at the transaction boundary + } else { + state.IntermediateRoot(true) // call intermediateRoot at the transaction boundary + } + } + action.fn(action, state) + } + if byzantium { + state.Finalise(true) // call finalise at the transaction boundary + } else { + state.IntermediateRoot(true) // call intermediateRoot at the transaction boundary + } + nroot, err := state.Commit(0, true) // call commit at the block boundary + if err != nil { + panic(err) + } + if nroot == root { + return true // filter out non-change state transition + } + roots = append(roots, nroot) + } + for i := 0; i < len(test.actions); i++ { + root := types.EmptyRootHash + if i != 0 { + root = roots[i-1] + } + test.err = test.verify(root, roots[i], tdb, accountList[i], storageList[i]) + if test.err != nil { + return false + } + } + return true +} + +// verifyAccountCreation this function is called once the state diff says that +// specific account was not present. A serial of checks will be performed to +// ensure the state diff is correct, includes: +// +// - the account was indeed not present in trie +// - the account is present in new trie, nil->nil is regarded as invalid +// - the slots transition is correct +func (test *stateTest) verifyAccountCreation(next common.Hash, db *trie.Database, otr, ntr *trie.Trie, addr common.Address, slots map[common.Hash][]byte) error { + // Verify account change + addrHash := crypto.Keccak256Hash(addr.Bytes()) + oBlob, err := otr.Get(addrHash.Bytes()) + if err != nil { + return err + } + nBlob, err := ntr.Get(addrHash.Bytes()) + if err != nil { + return err + } + if len(oBlob) != 0 { + return fmt.Errorf("unexpected account in old trie, %x", addrHash) + } + if len(nBlob) == 0 { + return fmt.Errorf("missing account in new trie, %x", addrHash) + } + + // Verify storage changes + var nAcct types.StateAccount + if err := rlp.DecodeBytes(nBlob, &nAcct); err != nil { + return err + } + // Account has no slot, empty slot set is expected + if nAcct.Root == types.EmptyRootHash { + if len(slots) != 0 { + return fmt.Errorf("unexpected slot changes %x", addrHash) + } + return nil + } + // Account has slots, ensure all new slots are contained + st, err := trie.New(trie.StorageTrieID(next, addrHash, nAcct.Root), db) + if err != nil { + return err + } + for key, val := range slots { + st.Update(key.Bytes(), val) + } + if st.Hash() != types.EmptyRootHash { + return errors.New("invalid slot changes") + } + return nil +} + +// verifyAccountUpdate this function is called once the state diff says that +// specific account was present. A serial of checks will be performed to +// ensure the state diff is correct, includes: +// +// - the account was indeed present in trie +// - the account in old trie matches the provided value +// - the slots transition is correct +func (test *stateTest) verifyAccountUpdate(next common.Hash, db *trie.Database, otr, ntr *trie.Trie, addr common.Address, origin []byte, slots map[common.Hash][]byte) error { + // Verify account change + addrHash := crypto.Keccak256Hash(addr.Bytes()) + oBlob, err := otr.Get(addrHash.Bytes()) + if err != nil { + return err + } + nBlob, err := ntr.Get(addrHash.Bytes()) + if err != nil { + return err + } + if len(oBlob) == 0 { + return fmt.Errorf("missing account in old trie, %x", addrHash) + } + full, err := types.FullAccountRLP(origin) + if err != nil { + return err + } + if !bytes.Equal(full, oBlob) { + return fmt.Errorf("account value is not matched, %x", addrHash) + } + + // Decode accounts + var ( + oAcct types.StateAccount + nAcct types.StateAccount + nRoot common.Hash + ) + if err := rlp.DecodeBytes(oBlob, &oAcct); err != nil { + return err + } + if len(nBlob) == 0 { + nRoot = types.EmptyRootHash + } else { + if err := rlp.DecodeBytes(nBlob, &nAcct); err != nil { + return err + } + nRoot = nAcct.Root + } + + // Verify storage + st, err := trie.New(trie.StorageTrieID(next, addrHash, nRoot), db) + if err != nil { + return err + } + for key, val := range slots { + st.Update(key.Bytes(), val) + } + if st.Hash() != oAcct.Root { + return errors.New("invalid slot changes") + } + return nil +} + +func (test *stateTest) verify(root common.Hash, next common.Hash, db *trie.Database, accountsOrigin map[common.Address][]byte, storagesOrigin map[common.Address]map[common.Hash][]byte) error { + otr, err := trie.New(trie.StateTrieID(root), db) + if err != nil { + return err + } + ntr, err := trie.New(trie.StateTrieID(next), db) + if err != nil { + return err + } + for addr, account := range accountsOrigin { + var err error + if len(account) == 0 { + err = test.verifyAccountCreation(next, db, otr, ntr, addr, storagesOrigin[addr]) + } else { + err = test.verifyAccountUpdate(next, db, otr, ntr, addr, accountsOrigin[addr], storagesOrigin[addr]) + } + if err != nil { + return err + } + } + return nil +} + +func TestStateChanges(t *testing.T) { + config := &quick.Config{MaxCount: 1000} + err := quick.Check((*stateTest).run, config) + if cerr, ok := err.(*quick.CheckError); ok { + test := cerr.In[0].(*stateTest) + t.Errorf("%v:\n%s", test.err, test) + } else if err != nil { + t.Error(err) + } +} diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go index e73b1b8c6e..ad829a0c8f 100644 --- a/core/state/statedb_test.go +++ b/core/state/statedb_test.go @@ -19,6 +19,7 @@ package state import ( "bytes" "encoding/binary" + "errors" "fmt" "math" "math/big" @@ -31,15 +32,26 @@ 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/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/triedb/hashdb" + "github.com/ethereum/go-ethereum/trie/triedb/pathdb" + "github.com/ethereum/go-ethereum/trie/trienode" + "github.com/holiman/uint256" ) // Tests that updating a state trie does not leak any database writes prior to // actually committing the state. func TestUpdateLeaks(t *testing.T) { // Create an empty state database - db := rawdb.NewMemoryDatabase() - state, _ := New(types.EmptyRootHash, NewDatabase(db), nil) + var ( + db = rawdb.NewMemoryDatabase() + tdb = trie.NewDatabase(db, nil) + ) + state, _ := New(types.EmptyRootHash, NewDatabaseWithNodeDB(db, tdb), nil) // Update it with some accounts for i := byte(0); i < 255; i++ { @@ -55,7 +67,7 @@ func TestUpdateLeaks(t *testing.T) { } root := state.IntermediateRoot(false) - if err := state.Database().TrieDB().Commit(root, false); err != nil { + if err := tdb.Commit(root, false); err != nil { t.Errorf("can not commit trie %v to persistent database", root.Hex()) } @@ -73,8 +85,10 @@ func TestIntermediateLeaks(t *testing.T) { // Create two state databases, one transitioning to the final state, the other final from the beginning transDb := rawdb.NewMemoryDatabase() finalDb := rawdb.NewMemoryDatabase() - transState, _ := New(types.EmptyRootHash, NewDatabase(transDb), nil) - finalState, _ := New(types.EmptyRootHash, NewDatabase(finalDb), nil) + transNdb := trie.NewDatabase(transDb, nil) + finalNdb := trie.NewDatabase(finalDb, nil) + transState, _ := New(types.EmptyRootHash, NewDatabaseWithNodeDB(transDb, transNdb), nil) + finalState, _ := New(types.EmptyRootHash, NewDatabaseWithNodeDB(finalDb, finalNdb), nil) modify := func(state *StateDB, addr common.Address, i, tweak byte) { state.SetBalance(addr, big.NewInt(int64(11*i)+int64(tweak))) @@ -102,19 +116,19 @@ func TestIntermediateLeaks(t *testing.T) { } // Commit and cross check the databases. - transRoot, err := transState.Commit(false) + transRoot, err := transState.Commit(0, false) if err != nil { t.Fatalf("failed to commit transition state: %v", err) } - if err = transState.Database().TrieDB().Commit(transRoot, false); err != nil { + if err = transNdb.Commit(transRoot, false); err != nil { t.Errorf("can not commit trie %v to persistent database", transRoot.Hex()) } - finalRoot, err := finalState.Commit(false) + finalRoot, err := finalState.Commit(0, false) if err != nil { t.Fatalf("failed to commit final state: %v", err) } - if err = finalState.Database().TrieDB().Commit(finalRoot, false); err != nil { + if err = finalNdb.Commit(finalRoot, false); err != nil { t.Errorf("can not commit trie %v to persistent database", finalRoot.Hex()) } @@ -297,9 +311,9 @@ func newTestAction(addr common.Address, r *rand.Rand) testAction { }, }, { - name: "Suicide", + name: "SelfDestruct", fn: func(a testAction, s *StateDB) { - s.Suicide(addr) + s.SelfDestruct(addr) }, }, { @@ -436,6 +450,43 @@ func (test *snapshotTest) run() bool { return true } +func forEachStorage(s *StateDB, addr common.Address, cb func(key, value common.Hash) bool) error { + so := s.getStateObject(addr) + if so == nil { + return nil + } + tr, err := so.getTrie() + if err != nil { + return err + } + trieIt, err := tr.NodeIterator(nil) + if err != nil { + return err + } + it := trie.NewIterator(trieIt) + + for it.Next() { + key := common.BytesToHash(s.trie.GetKey(it.Key)) + if value, dirty := so.dirtyStorage[key]; dirty { + if !cb(key, value) { + return nil + } + continue + } + + if len(it.Value) > 0 { + _, content, _, err := rlp.Split(it.Value) + if err != nil { + return err + } + if !cb(key, common.BytesToHash(content)) { + return nil + } + } + } + return nil +} + // checkEqual checks that methods of state and checkstate return the same values. func (test *snapshotTest) checkEqual(state, checkstate *StateDB) error { for _, addr := range test.addrs { @@ -449,7 +500,7 @@ func (test *snapshotTest) checkEqual(state, checkstate *StateDB) error { } // Check basic accessor methods. checkeq("Exist", state.Exist(addr), checkstate.Exist(addr)) - checkeq("HasSuicided", state.HasSuicided(addr), checkstate.HasSuicided(addr)) + checkeq("HasSelfdestructed", state.HasSelfDestructed(addr), checkstate.HasSelfDestructed(addr)) checkeq("GetBalance", state.GetBalance(addr), checkstate.GetBalance(addr)) checkeq("GetNonce", state.GetNonce(addr), checkstate.GetNonce(addr)) checkeq("GetCode", state.GetCode(addr), checkstate.GetCode(addr)) @@ -457,10 +508,10 @@ func (test *snapshotTest) checkEqual(state, checkstate *StateDB) error { checkeq("GetCodeSize", state.GetCodeSize(addr), checkstate.GetCodeSize(addr)) // Check storage. if obj := state.getStateObject(addr); obj != nil { - state.ForEachStorage(addr, func(key, value common.Hash) bool { + forEachStorage(state, addr, func(key, value common.Hash) bool { return checkeq("GetState("+key.Hex()+")", checkstate.GetState(addr, key), value) }) - checkstate.ForEachStorage(addr, func(key, value common.Hash) bool { + forEachStorage(checkstate, addr, func(key, value common.Hash) bool { return checkeq("GetState("+key.Hex()+")", checkstate.GetState(addr, key), value) }) } @@ -481,9 +532,9 @@ func (test *snapshotTest) checkEqual(state, checkstate *StateDB) error { } func TestTouchDelete(t *testing.T) { - s := newStateTest() + s := newStateEnv() s.state.GetOrNewStateObject(common.Address{}) - root, _ := s.state.Commit(false) + root, _ := s.state.Commit(0, false) s.state, _ = New(root, s.state.db, s.state.snaps) snapshot := s.state.Snapshot() @@ -518,7 +569,8 @@ func TestCopyOfCopy(t *testing.T) { // // See https://github.com/ethereum/go-ethereum/issues/20106. func TestCopyCommitCopy(t *testing.T) { - state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) + tdb := NewDatabase(rawdb.NewMemoryDatabase()) + state, _ := New(types.EmptyRootHash, tdb, nil) // Create an account and check if the retrieved balance is correct addr := common.HexToAddress("0xaffeaffeaffeaffeaffeaffeaffeaffeaffeaffe") @@ -555,20 +607,6 @@ func TestCopyCommitCopy(t *testing.T) { if val := copyOne.GetCommittedState(addr, skey); val != (common.Hash{}) { t.Fatalf("first copy pre-commit committed storage slot mismatch: have %x, want %x", val, common.Hash{}) } - - copyOne.Commit(false) - if balance := copyOne.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { - t.Fatalf("first copy post-commit balance mismatch: have %v, want %v", balance, 42) - } - if code := copyOne.GetCode(addr); !bytes.Equal(code, []byte("hello")) { - t.Fatalf("first copy post-commit code mismatch: have %x, want %x", code, []byte("hello")) - } - if val := copyOne.GetState(addr, skey); val != sval { - t.Fatalf("first copy post-commit non-committed storage slot mismatch: have %x, want %x", val, sval) - } - if val := copyOne.GetCommittedState(addr, skey); val != sval { - t.Fatalf("first copy post-commit committed storage slot mismatch: have %x, want %x", val, sval) - } // Copy the copy and check the balance once more copyTwo := copyOne.Copy() if balance := copyTwo.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { @@ -580,8 +618,23 @@ func TestCopyCommitCopy(t *testing.T) { if val := copyTwo.GetState(addr, skey); val != sval { t.Fatalf("second copy non-committed storage slot mismatch: have %x, want %x", val, sval) } - if val := copyTwo.GetCommittedState(addr, skey); val != sval { - t.Fatalf("second copy post-commit committed storage slot mismatch: have %x, want %x", val, sval) + if val := copyTwo.GetCommittedState(addr, skey); val != (common.Hash{}) { + t.Fatalf("second copy committed storage slot mismatch: have %x, want %x", val, sval) + } + // Commit state, ensure states can be loaded from disk + root, _ := state.Commit(0, false) + state, _ = New(root, tdb, nil) + if balance := state.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { + t.Fatalf("state post-commit balance mismatch: have %v, want %v", balance, 42) + } + if code := state.GetCode(addr); !bytes.Equal(code, []byte("hello")) { + t.Fatalf("state post-commit code mismatch: have %x, want %x", code, []byte("hello")) + } + if val := state.GetState(addr, skey); val != sval { + t.Fatalf("state post-commit non-committed storage slot mismatch: have %x, want %x", val, sval) + } + if val := state.GetCommittedState(addr, skey); val != sval { + t.Fatalf("state post-commit committed storage slot mismatch: have %x, want %x", val, sval) } } @@ -641,19 +694,6 @@ func TestCopyCopyCommitCopy(t *testing.T) { if val := copyTwo.GetCommittedState(addr, skey); val != (common.Hash{}) { t.Fatalf("second copy pre-commit committed storage slot mismatch: have %x, want %x", val, common.Hash{}) } - copyTwo.Commit(false) - if balance := copyTwo.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { - t.Fatalf("second copy post-commit balance mismatch: have %v, want %v", balance, 42) - } - if code := copyTwo.GetCode(addr); !bytes.Equal(code, []byte("hello")) { - t.Fatalf("second copy post-commit code mismatch: have %x, want %x", code, []byte("hello")) - } - if val := copyTwo.GetState(addr, skey); val != sval { - t.Fatalf("second copy post-commit non-committed storage slot mismatch: have %x, want %x", val, sval) - } - if val := copyTwo.GetCommittedState(addr, skey); val != sval { - t.Fatalf("second copy post-commit committed storage slot mismatch: have %x, want %x", val, sval) - } // Copy the copy-copy and check the balance once more copyThree := copyTwo.Copy() if balance := copyThree.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { @@ -665,11 +705,56 @@ func TestCopyCopyCommitCopy(t *testing.T) { if val := copyThree.GetState(addr, skey); val != sval { t.Fatalf("third copy non-committed storage slot mismatch: have %x, want %x", val, sval) } - if val := copyThree.GetCommittedState(addr, skey); val != sval { + if val := copyThree.GetCommittedState(addr, skey); val != (common.Hash{}) { t.Fatalf("third copy committed storage slot mismatch: have %x, want %x", val, sval) } } +// TestCommitCopy tests the copy from a committed state is not functional. +func TestCommitCopy(t *testing.T) { + state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) + + // Create an account and check if the retrieved balance is correct + addr := common.HexToAddress("0xaffeaffeaffeaffeaffeaffeaffeaffeaffeaffe") + skey := common.HexToHash("aaa") + sval := common.HexToHash("bbb") + + state.SetBalance(addr, big.NewInt(42)) // 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(big.NewInt(42)) != 0 { + t.Fatalf("initial balance mismatch: have %v, want %v", balance, 42) + } + 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.GetCommittedState(addr, skey); 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) + copied := state.Copy() + if balance := copied.GetBalance(addr); balance.Cmp(big.NewInt(0)) != 0 { + t.Fatalf("unexpected balance: have %v", balance) + } + if code := copied.GetCode(addr); code != nil { + t.Fatalf("unexpected code: have %x", code) + } + if val := copied.GetState(addr, skey); val != (common.Hash{}) { + t.Fatalf("unexpected storage slot: have %x", val) + } + if val := copied.GetCommittedState(addr, skey); val != (common.Hash{}) { + 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 // while changing the internals of StateDB. The workflow is that a contract is // self-destructed, then in a follow-up transaction (but same block) it's created @@ -685,11 +770,11 @@ func TestDeleteCreateRevert(t *testing.T) { addr := common.BytesToAddress([]byte("so")) state.SetBalance(addr, big.NewInt(1)) - root, _ := state.Commit(false) + root, _ := state.Commit(0, false) state, _ = New(root, state.db, state.snaps) // Simulate self-destructing in one transaction, then create-reverting in another - state.Suicide(addr) + state.SelfDestruct(addr) state.Finalise(true) id := state.Snapshot() @@ -697,7 +782,7 @@ func TestDeleteCreateRevert(t *testing.T) { state.RevertToSnapshot(id) // Commit the entire state and make sure we don't crash and have the correct state - root, _ = state.Commit(true) + root, _ = state.Commit(0, true) state, _ = New(root, state.db, state.snaps) if state.getStateObject(addr) != nil { @@ -709,9 +794,28 @@ func TestDeleteCreateRevert(t *testing.T) { // the Commit operation fails with an error // If we are missing trie nodes, we should not continue writing to the trie func TestMissingTrieNodes(t *testing.T) { + testMissingTrieNodes(t, rawdb.HashScheme) + testMissingTrieNodes(t, rawdb.PathScheme) +} + +func testMissingTrieNodes(t *testing.T, scheme string) { // Create an initial state with a few accounts - memDb := rawdb.NewMemoryDatabase() - db := NewDatabase(memDb) + var ( + triedb *trie.Database + memDb = rawdb.NewMemoryDatabase() + ) + if scheme == rawdb.PathScheme { + triedb = trie.NewDatabase(memDb, &trie.Config{PathDB: &pathdb.Config{ + CleanCacheSize: 0, + DirtyCacheSize: 0, + }}) // disable caching + } else { + triedb = trie.NewDatabase(memDb, &trie.Config{HashDB: &hashdb.Config{ + CleanCacheSize: 0, + }}) // disable caching + } + db := NewDatabaseWithNodeDB(memDb, triedb) + var root common.Hash state, _ := New(types.EmptyRootHash, db, nil) addr := common.BytesToAddress([]byte("so")) @@ -721,10 +825,10 @@ func TestMissingTrieNodes(t *testing.T) { a2 := common.BytesToAddress([]byte("another")) state.SetBalance(a2, big.NewInt(100)) state.SetCode(a2, []byte{1, 2, 4}) - root, _ = state.Commit(false) + root, _ = state.Commit(0, false) t.Logf("root: %x", root) // force-flush - state.Database().TrieDB().Cap(0) + triedb.Commit(root, false) } // Create a new state on the old root state, _ = New(root, db, nil) @@ -745,7 +849,7 @@ func TestMissingTrieNodes(t *testing.T) { } // Modify the state state.SetBalance(addr, big.NewInt(2)) - root, err := state.Commit(false) + root, err := state.Commit(0, false) if err == nil { t.Fatalf("expected error, got root :%x", root) } @@ -931,7 +1035,8 @@ func TestFlushOrderDataLoss(t *testing.T) { // Create a state trie with many accounts and slots var ( memdb = rawdb.NewMemoryDatabase() - statedb = NewDatabase(memdb) + triedb = trie.NewDatabase(memdb, nil) + statedb = NewDatabaseWithNodeDB(memdb, triedb) state, _ = New(types.EmptyRootHash, statedb, nil) ) for a := byte(0); a < 10; a++ { @@ -940,15 +1045,15 @@ func TestFlushOrderDataLoss(t *testing.T) { state.SetState(common.Address{a}, common.Hash{a, s}, common.Hash{a, s}) } } - root, err := state.Commit(false) + root, err := state.Commit(0, false) if err != nil { t.Fatalf("failed to commit state trie: %v", err) } - statedb.TrieDB().Reference(root, common.Hash{}) - if err := statedb.TrieDB().Cap(1024); err != nil { + triedb.Reference(root, common.Hash{}) + if err := triedb.Cap(1024); err != nil { t.Fatalf("failed to cap trie dirty cache: %v", err) } - if err := statedb.TrieDB().Commit(root, false); err != nil { + if err := triedb.Commit(root, false); err != nil { t.Fatalf("failed to commit state trie: %v", err) } // Reopen the state trie from flushed disk and verify it @@ -998,3 +1103,91 @@ func TestStateDBTransientStorage(t *testing.T) { t.Fatalf("transient storage mismatch: have %x, want %x", got, value) } } + +func TestResetObject(t *testing.T) { + var ( + disk = rawdb.NewMemoryDatabase() + tdb = trie.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, big.NewInt(1)) + state.SetState(addr, slotA, common.BytesToHash([]byte{0x1})) + state.IntermediateRoot(true) + + // Reset account and mutate balance and storages + state.CreateAccount(addr) + state.SetBalance(addr, big.NewInt(2)) + 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() + tdb = trie.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") + ) + // Initialize account and populate storage + state.SetBalance(addr, big.NewInt(1)) + state.CreateAccount(addr) + for i := 0; i < 1000; i++ { + slot := common.Hash(uint256.NewInt(uint64(i)).Bytes32()) + value := common.Hash(uint256.NewInt(uint64(10 * i)).Bytes32()) + 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) + + obj := fastState.GetOrNewStateObject(addr) + storageRoot := obj.data.Root + + _, _, fastNodes, err := fastState.deleteStorage(addr, crypto.Keccak256Hash(addr[:]), storageRoot) + if err != nil { + t.Fatal(err) + } + + _, _, slowNodes, err := slowState.deleteStorage(addr, crypto.Keccak256Hash(addr[:]), storageRoot) + if err != nil { + t.Fatal(err) + } + check := func(set *trienode.NodeSet) string { + var a []string + set.ForEachWithOrder(func(path string, n *trienode.Node) { + if n.Hash != (common.Hash{}) { + t.Fatal("delete should have empty hashes") + } + if len(n.Blob) != 0 { + t.Fatal("delete should have have empty blobs") + } + a = append(a, fmt.Sprintf("%x", path)) + }) + return strings.Join(a, ",") + } + slowRes := check(slowNodes) + fastRes := check(fastNodes) + if slowRes != fastRes { + t.Fatalf("difference found:\nfast: %v\nslow: %v\n", fastRes, slowRes) + } +} diff --git a/core/state/sync.go b/core/state/sync.go index 61097c6462..d6775e8896 100644 --- a/core/state/sync.go +++ b/core/state/sync.go @@ -17,8 +17,6 @@ package state import ( - "bytes" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethdb" @@ -45,7 +43,7 @@ func NewStateSync(root common.Hash, database ethdb.KeyValueReader, onLeaf func(k } } var obj types.StateAccount - if err := rlp.Decode(bytes.NewReader(leaf), &obj); err != nil { + if err := rlp.DecodeBytes(leaf, &obj); err != nil { return err } syncer.AddSubTrie(obj.Root, path, parent, parentPath, onSlot) diff --git a/core/state/sync_test.go b/core/state/sync_test.go index 6e9d9342ee..6196e77817 100644 --- a/core/state/sync_test.go +++ b/core/state/sync_test.go @@ -28,6 +28,8 @@ import ( "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" + "github.com/ethereum/go-ethereum/trie/triedb/hashdb" + "github.com/ethereum/go-ethereum/trie/triedb/pathdb" ) // testAccount is the data associated with an account used by the state tests. @@ -39,10 +41,17 @@ type testAccount struct { } // makeTestState create a sample test state to test node-wise reconstruction. -func makeTestState() (ethdb.Database, Database, common.Hash, []*testAccount) { +func makeTestState(scheme string) (ethdb.Database, Database, *trie.Database, common.Hash, []*testAccount) { // Create an empty state + config := &trie.Config{Preimages: true} + if scheme == rawdb.PathScheme { + config.PathDB = pathdb.Defaults + } else { + config.HashDB = hashdb.Defaults + } db := rawdb.NewMemoryDatabase() - sdb := NewDatabase(db) + nodeDb := trie.NewDatabase(db, config) + sdb := NewDatabaseWithNodeDB(db, nodeDb) state, _ := New(types.EmptyRootHash, sdb, nil) // Fill it with some arbitrary data @@ -64,27 +73,30 @@ func makeTestState() (ethdb.Database, Database, common.Hash, []*testAccount) { if i%5 == 0 { for j := byte(0); j < 5; j++ { hash := crypto.Keccak256Hash([]byte{i, i, i, i, i, j, j}) - obj.SetState(sdb, hash, hash) + obj.SetState(hash, hash) } } - state.updateStateObject(obj) accounts = append(accounts, acc) } - root, _ := state.Commit(false) + root, _ := state.Commit(0, false) // Return the generated state - return db, sdb, root, accounts + return db, sdb, nodeDb, root, accounts } // checkStateAccounts cross references a reconstructed state with an expected // account array. -func checkStateAccounts(t *testing.T, db ethdb.Database, root common.Hash, accounts []*testAccount) { +func checkStateAccounts(t *testing.T, db ethdb.Database, scheme string, root common.Hash, accounts []*testAccount) { + var config trie.Config + if scheme == rawdb.PathScheme { + config.PathDB = pathdb.Defaults + } // Check root availability and state contents - state, err := New(root, NewDatabase(db), nil) + state, err := New(root, NewDatabaseWithConfig(db, &config), nil) if err != nil { t.Fatalf("failed to create state trie at %x: %v", root, err) } - if err := checkStateConsistency(db, root); err != nil { + if err := checkStateConsistency(db, scheme, root); err != nil { t.Fatalf("inconsistent state trie at %x: %v", root, err) } for i, acc := range accounts { @@ -100,28 +112,13 @@ func checkStateAccounts(t *testing.T, db ethdb.Database, root common.Hash, accou } } -// checkTrieConsistency checks that all nodes in a (sub-)trie are indeed present. -func checkTrieConsistency(db ethdb.Database, root common.Hash) error { - if v, _ := db.Get(root[:]); v == nil { - return nil // Consider a non existent state consistent. - } - trie, err := trie.New(trie.StateTrieID(root), trie.NewDatabase(db)) - if err != nil { - return err - } - it := trie.NodeIterator(nil) - for it.Next(true) { - } - return it.Error() -} - // checkStateConsistency checks that all data of a state root is present. -func checkStateConsistency(db ethdb.Database, root common.Hash) error { - // Create and iterate a state trie rooted in a sub-node - if _, err := db.Get(root.Bytes()); err != nil { - return nil // Consider a non existent state consistent. +func checkStateConsistency(db ethdb.Database, scheme string, root common.Hash) error { + config := &trie.Config{Preimages: true} + if scheme == rawdb.PathScheme { + config.PathDB = pathdb.Defaults } - state, err := New(root, NewDatabase(db), nil) + state, err := New(root, NewDatabaseWithConfig(db, config), nil) if err != nil { return err } @@ -133,8 +130,14 @@ func checkStateConsistency(db ethdb.Database, root common.Hash) error { // Tests that an empty state is not scheduled for syncing. func TestEmptyStateSync(t *testing.T) { - db := trie.NewDatabase(rawdb.NewMemoryDatabase()) - sync := NewStateSync(types.EmptyRootHash, rawdb.NewMemoryDatabase(), nil, db.Scheme()) + dbA := trie.NewDatabase(rawdb.NewMemoryDatabase(), nil) + dbB := trie.NewDatabase(rawdb.NewMemoryDatabase(), &trie.Config{PathDB: pathdb.Defaults}) + + sync := NewStateSync(types.EmptyRootHash, rawdb.NewMemoryDatabase(), nil, dbA.Scheme()) + if paths, nodes, codes := sync.Missing(1); len(paths) != 0 || len(nodes) != 0 || len(codes) != 0 { + t.Errorf("content requested for empty state: %v, %v, %v", nodes, paths, codes) + } + sync = NewStateSync(types.EmptyRootHash, rawdb.NewMemoryDatabase(), nil, dbB.Scheme()) if paths, nodes, codes := sync.Missing(1); len(paths) != 0 || len(nodes) != 0 || len(codes) != 0 { t.Errorf("content requested for empty state: %v, %v, %v", nodes, paths, codes) } @@ -143,22 +146,28 @@ func TestEmptyStateSync(t *testing.T) { // Tests that given a root hash, a state can sync iteratively on a single thread, // requesting retrieval tasks and returning all of them in one go. func TestIterativeStateSyncIndividual(t *testing.T) { - testIterativeStateSync(t, 1, false, false) + testIterativeStateSync(t, 1, false, false, rawdb.HashScheme) + testIterativeStateSync(t, 1, false, false, rawdb.PathScheme) } func TestIterativeStateSyncBatched(t *testing.T) { - testIterativeStateSync(t, 100, false, false) + testIterativeStateSync(t, 100, false, false, rawdb.HashScheme) + testIterativeStateSync(t, 100, false, false, rawdb.PathScheme) } func TestIterativeStateSyncIndividualFromDisk(t *testing.T) { - testIterativeStateSync(t, 1, true, false) + testIterativeStateSync(t, 1, true, false, rawdb.HashScheme) + testIterativeStateSync(t, 1, true, false, rawdb.PathScheme) } func TestIterativeStateSyncBatchedFromDisk(t *testing.T) { - testIterativeStateSync(t, 100, true, false) + testIterativeStateSync(t, 100, true, false, rawdb.HashScheme) + testIterativeStateSync(t, 100, true, false, rawdb.PathScheme) } func TestIterativeStateSyncIndividualByPath(t *testing.T) { - testIterativeStateSync(t, 1, false, true) + testIterativeStateSync(t, 1, false, true, rawdb.HashScheme) + testIterativeStateSync(t, 1, false, true, rawdb.PathScheme) } func TestIterativeStateSyncBatchedByPath(t *testing.T) { - testIterativeStateSync(t, 100, false, true) + testIterativeStateSync(t, 100, false, true, rawdb.HashScheme) + testIterativeStateSync(t, 100, false, true, rawdb.PathScheme) } // stateElement represents the element in the state trie(bytecode or trie node). @@ -169,17 +178,17 @@ type stateElement struct { syncPath trie.SyncPath } -func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool) { +func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool, scheme string) { // Create a random state to copy - _, srcDb, srcRoot, srcAccounts := makeTestState() + srcDisk, srcDb, ndb, srcRoot, srcAccounts := makeTestState(scheme) if commit { - srcDb.TrieDB().Commit(srcRoot, false) + ndb.Commit(srcRoot, false) } - srcTrie, _ := trie.New(trie.StateTrieID(srcRoot), srcDb.TrieDB()) + srcTrie, _ := trie.New(trie.StateTrieID(srcRoot), ndb) // Create a destination state and sync with the scheduler dstDb := rawdb.NewMemoryDatabase() - sched := NewStateSync(srcRoot, dstDb, nil, srcDb.TrieDB().Scheme()) + sched := NewStateSync(srcRoot, dstDb, nil, ndb.Scheme()) var ( nodeElements []stateElement @@ -194,9 +203,11 @@ func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool) { }) } for i := 0; i < len(codes); i++ { - codeElements = append(codeElements, stateElement{ - code: codes[i], - }) + codeElements = append(codeElements, stateElement{code: codes[i]}) + } + reader, err := ndb.Reader(srcRoot) + if err != nil { + t.Fatalf("state is not existent, %#x", srcRoot) } for len(nodeElements)+len(codeElements) > 0 { var ( @@ -204,7 +215,7 @@ func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool) { codeResults = make([]trie.CodeSyncResult, len(codeElements)) ) for i, element := range codeElements { - data, err := srcDb.ContractCode(common.Hash{}, element.code) + data, err := srcDb.ContractCode(common.Address{}, element.code) if err != nil { t.Fatalf("failed to retrieve contract bytecode for hash %x", element.code) } @@ -224,7 +235,7 @@ func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool) { t.Fatalf("failed to decode account on path %x: %v", node.syncPath[0], err) } id := trie.StorageTrieID(srcRoot, common.BytesToHash(node.syncPath[0]), acc.Root) - stTrie, err := trie.New(id, srcDb.TrieDB()) + stTrie, err := trie.New(id, ndb) if err != nil { t.Fatalf("failed to retriev storage trie for path %x: %v", node.syncPath[1], err) } @@ -235,7 +246,8 @@ func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool) { nodeResults[i] = trie.NodeSyncResult{Path: node.path, Data: data} } } else { - data, err := srcDb.TrieDB().Node(node.hash) + owner, inner := trie.ResolvePath([]byte(node.path)) + data, err := reader.Node(owner, inner, node.hash) if err != nil { t.Fatalf("failed to retrieve node data for key %v", []byte(node.path)) } @@ -274,19 +286,28 @@ func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool) { }) } } + // Copy the preimages from source db in order to traverse the state. + srcDb.TrieDB().WritePreimages() + copyPreimages(srcDisk, dstDb) + // Cross check that the two states are in sync - checkStateAccounts(t, dstDb, srcRoot, srcAccounts) + checkStateAccounts(t, dstDb, ndb.Scheme(), srcRoot, srcAccounts) } // Tests that the trie scheduler can correctly reconstruct the state even if only // partial results are returned, and the others sent only later. func TestIterativeDelayedStateSync(t *testing.T) { + testIterativeDelayedStateSync(t, rawdb.HashScheme) + testIterativeDelayedStateSync(t, rawdb.PathScheme) +} + +func testIterativeDelayedStateSync(t *testing.T, scheme string) { // Create a random state to copy - _, srcDb, srcRoot, srcAccounts := makeTestState() + srcDisk, srcDb, ndb, srcRoot, srcAccounts := makeTestState(scheme) // Create a destination state and sync with the scheduler dstDb := rawdb.NewMemoryDatabase() - sched := NewStateSync(srcRoot, dstDb, nil, srcDb.TrieDB().Scheme()) + sched := NewStateSync(srcRoot, dstDb, nil, ndb.Scheme()) var ( nodeElements []stateElement @@ -301,9 +322,11 @@ func TestIterativeDelayedStateSync(t *testing.T) { }) } for i := 0; i < len(codes); i++ { - codeElements = append(codeElements, stateElement{ - code: codes[i], - }) + codeElements = append(codeElements, stateElement{code: codes[i]}) + } + reader, err := ndb.Reader(srcRoot) + if err != nil { + t.Fatalf("state is not existent, %#x", srcRoot) } for len(nodeElements)+len(codeElements) > 0 { // Sync only half of the scheduled nodes @@ -312,7 +335,7 @@ func TestIterativeDelayedStateSync(t *testing.T) { if len(codeElements) > 0 { codeResults := make([]trie.CodeSyncResult, len(codeElements)/2+1) for i, element := range codeElements[:len(codeResults)] { - data, err := srcDb.ContractCode(common.Hash{}, element.code) + data, err := srcDb.ContractCode(common.Address{}, element.code) if err != nil { t.Fatalf("failed to retrieve contract bytecode for %x", element.code) } @@ -328,7 +351,8 @@ func TestIterativeDelayedStateSync(t *testing.T) { if len(nodeElements) > 0 { nodeResults := make([]trie.NodeSyncResult, len(nodeElements)/2+1) for i, element := range nodeElements[:len(nodeResults)] { - data, err := srcDb.TrieDB().Node(element.hash) + owner, inner := trie.ResolvePath([]byte(element.path)) + data, err := reader.Node(owner, inner, element.hash) if err != nil { t.Fatalf("failed to retrieve contract bytecode for %x", element.code) } @@ -363,23 +387,33 @@ func TestIterativeDelayedStateSync(t *testing.T) { }) } } + // Copy the preimages from source db in order to traverse the state. + srcDb.TrieDB().WritePreimages() + copyPreimages(srcDisk, dstDb) + // Cross check that the two states are in sync - checkStateAccounts(t, dstDb, srcRoot, srcAccounts) + checkStateAccounts(t, dstDb, ndb.Scheme(), srcRoot, srcAccounts) } // Tests that given a root hash, a trie can sync iteratively on a single thread, // requesting retrieval tasks and returning all of them in one go, however in a // random order. -func TestIterativeRandomStateSyncIndividual(t *testing.T) { testIterativeRandomStateSync(t, 1) } -func TestIterativeRandomStateSyncBatched(t *testing.T) { testIterativeRandomStateSync(t, 100) } +func TestIterativeRandomStateSyncIndividual(t *testing.T) { + testIterativeRandomStateSync(t, 1, rawdb.HashScheme) + testIterativeRandomStateSync(t, 1, rawdb.PathScheme) +} +func TestIterativeRandomStateSyncBatched(t *testing.T) { + testIterativeRandomStateSync(t, 100, rawdb.HashScheme) + testIterativeRandomStateSync(t, 100, rawdb.PathScheme) +} -func testIterativeRandomStateSync(t *testing.T, count int) { +func testIterativeRandomStateSync(t *testing.T, count int, scheme string) { // Create a random state to copy - _, srcDb, srcRoot, srcAccounts := makeTestState() + srcDisk, srcDb, ndb, srcRoot, srcAccounts := makeTestState(scheme) // Create a destination state and sync with the scheduler dstDb := rawdb.NewMemoryDatabase() - sched := NewStateSync(srcRoot, dstDb, nil, srcDb.TrieDB().Scheme()) + sched := NewStateSync(srcRoot, dstDb, nil, ndb.Scheme()) nodeQueue := make(map[string]stateElement) codeQueue := make(map[common.Hash]struct{}) @@ -394,12 +428,16 @@ func testIterativeRandomStateSync(t *testing.T, count int) { for _, hash := range codes { codeQueue[hash] = struct{}{} } + reader, err := ndb.Reader(srcRoot) + if err != nil { + t.Fatalf("state is not existent, %#x", srcRoot) + } for len(nodeQueue)+len(codeQueue) > 0 { // Fetch all the queued nodes in a random order if len(codeQueue) > 0 { results := make([]trie.CodeSyncResult, 0, len(codeQueue)) for hash := range codeQueue { - data, err := srcDb.ContractCode(common.Hash{}, hash) + data, err := srcDb.ContractCode(common.Address{}, hash) if err != nil { t.Fatalf("failed to retrieve node data for %x", hash) } @@ -414,7 +452,8 @@ func testIterativeRandomStateSync(t *testing.T, count int) { if len(nodeQueue) > 0 { results := make([]trie.NodeSyncResult, 0, len(nodeQueue)) for path, element := range nodeQueue { - data, err := srcDb.TrieDB().Node(element.hash) + owner, inner := trie.ResolvePath([]byte(element.path)) + data, err := reader.Node(owner, inner, element.hash) if err != nil { t.Fatalf("failed to retrieve node data for %x %v %v", element.hash, []byte(element.path), element.path) } @@ -426,7 +465,6 @@ func testIterativeRandomStateSync(t *testing.T, count int) { } } } - // Feed the retrieved results back and queue new tasks batch := dstDb.NewBatch() if err := sched.Commit(batch); err != nil { t.Fatalf("failed to commit data: %v", err) @@ -447,19 +485,28 @@ func testIterativeRandomStateSync(t *testing.T, count int) { codeQueue[hash] = struct{}{} } } + // Copy the preimages from source db in order to traverse the state. + srcDb.TrieDB().WritePreimages() + copyPreimages(srcDisk, dstDb) + // Cross check that the two states are in sync - checkStateAccounts(t, dstDb, srcRoot, srcAccounts) + checkStateAccounts(t, dstDb, ndb.Scheme(), srcRoot, srcAccounts) } // Tests that the trie scheduler can correctly reconstruct the state even if only // partial results are returned (Even those randomly), others sent only later. func TestIterativeRandomDelayedStateSync(t *testing.T) { + testIterativeRandomDelayedStateSync(t, rawdb.HashScheme) + testIterativeRandomDelayedStateSync(t, rawdb.PathScheme) +} + +func testIterativeRandomDelayedStateSync(t *testing.T, scheme string) { // Create a random state to copy - _, srcDb, srcRoot, srcAccounts := makeTestState() + srcDisk, srcDb, ndb, srcRoot, srcAccounts := makeTestState(scheme) // Create a destination state and sync with the scheduler dstDb := rawdb.NewMemoryDatabase() - sched := NewStateSync(srcRoot, dstDb, nil, srcDb.TrieDB().Scheme()) + sched := NewStateSync(srcRoot, dstDb, nil, ndb.Scheme()) nodeQueue := make(map[string]stateElement) codeQueue := make(map[common.Hash]struct{}) @@ -474,6 +521,10 @@ func TestIterativeRandomDelayedStateSync(t *testing.T) { for _, hash := range codes { codeQueue[hash] = struct{}{} } + reader, err := ndb.Reader(srcRoot) + if err != nil { + t.Fatalf("state is not existent, %#x", srcRoot) + } for len(nodeQueue)+len(codeQueue) > 0 { // Sync only half of the scheduled nodes, even those in random order if len(codeQueue) > 0 { @@ -481,7 +532,7 @@ func TestIterativeRandomDelayedStateSync(t *testing.T) { for hash := range codeQueue { delete(codeQueue, hash) - data, err := srcDb.ContractCode(common.Hash{}, hash) + data, err := srcDb.ContractCode(common.Address{}, hash) if err != nil { t.Fatalf("failed to retrieve node data for %x", hash) } @@ -502,7 +553,8 @@ func TestIterativeRandomDelayedStateSync(t *testing.T) { for path, element := range nodeQueue { delete(nodeQueue, path) - data, err := srcDb.TrieDB().Node(element.hash) + owner, inner := trie.ResolvePath([]byte(element.path)) + data, err := reader.Node(owner, inner, element.hash) if err != nil { t.Fatalf("failed to retrieve node data for %x", element.hash) } @@ -537,15 +589,24 @@ func TestIterativeRandomDelayedStateSync(t *testing.T) { codeQueue[hash] = struct{}{} } } + // Copy the preimages from source db in order to traverse the state. + srcDb.TrieDB().WritePreimages() + copyPreimages(srcDisk, dstDb) + // Cross check that the two states are in sync - checkStateAccounts(t, dstDb, srcRoot, srcAccounts) + checkStateAccounts(t, dstDb, ndb.Scheme(), srcRoot, srcAccounts) } // Tests that at any point in time during a sync, only complete sub-tries are in // the database. func TestIncompleteStateSync(t *testing.T) { + testIncompleteStateSync(t, rawdb.HashScheme) + testIncompleteStateSync(t, rawdb.PathScheme) +} + +func testIncompleteStateSync(t *testing.T, scheme string) { // Create a random state to copy - db, srcDb, srcRoot, srcAccounts := makeTestState() + db, srcDb, ndb, srcRoot, srcAccounts := makeTestState(scheme) // isCodeLookup to save some hashing var isCode = make(map[common.Hash]struct{}) @@ -555,17 +616,20 @@ func TestIncompleteStateSync(t *testing.T) { } } isCode[types.EmptyCodeHash] = struct{}{} - checkTrieConsistency(db, srcRoot) // Create a destination state and sync with the scheduler dstDb := rawdb.NewMemoryDatabase() - sched := NewStateSync(srcRoot, dstDb, nil, srcDb.TrieDB().Scheme()) + sched := NewStateSync(srcRoot, dstDb, nil, ndb.Scheme()) var ( addedCodes []common.Hash addedPaths []string addedHashes []common.Hash ) + reader, err := ndb.Reader(srcRoot) + if err != nil { + t.Fatalf("state is not available %x", srcRoot) + } nodeQueue := make(map[string]stateElement) codeQueue := make(map[common.Hash]struct{}) paths, nodes, codes := sched.Missing(1) @@ -584,7 +648,7 @@ func TestIncompleteStateSync(t *testing.T) { if len(codeQueue) > 0 { results := make([]trie.CodeSyncResult, 0, len(codeQueue)) for hash := range codeQueue { - data, err := srcDb.ContractCode(common.Hash{}, hash) + data, err := srcDb.ContractCode(common.Address{}, hash) if err != nil { t.Fatalf("failed to retrieve node data for %x", hash) } @@ -598,12 +662,11 @@ func TestIncompleteStateSync(t *testing.T) { } } } - var nodehashes []common.Hash if len(nodeQueue) > 0 { results := make([]trie.NodeSyncResult, 0, len(nodeQueue)) for path, element := range nodeQueue { owner, inner := trie.ResolvePath([]byte(element.path)) - data, err := srcDb.TrieDB().Reader(srcRoot).Node(owner, inner, element.hash) + data, err := reader.Node(owner, inner, element.hash) if err != nil { t.Fatalf("failed to retrieve node data for %x", element.hash) } @@ -613,7 +676,6 @@ func TestIncompleteStateSync(t *testing.T) { addedPaths = append(addedPaths, element.path) addedHashes = append(addedHashes, element.hash) } - nodehashes = append(nodehashes, element.hash) } // Process each of the state nodes for _, result := range results { @@ -628,13 +690,6 @@ func TestIncompleteStateSync(t *testing.T) { } batch.Write() - for _, root := range nodehashes { - // Can't use checkStateConsistency here because subtrie keys may have odd - // length and crash in LeafKey. - if err := checkTrieConsistency(dstDb, root); err != nil { - t.Fatalf("state inconsistent: %v", err) - } - } // Fetch the next batch to retrieve nodeQueue = make(map[string]stateElement) codeQueue = make(map[common.Hash]struct{}) @@ -650,16 +705,19 @@ func TestIncompleteStateSync(t *testing.T) { codeQueue[hash] = struct{}{} } } + // Copy the preimages from source db in order to traverse the state. + srcDb.TrieDB().WritePreimages() + copyPreimages(db, dstDb) + // Sanity check that removing any node from the database is detected for _, node := range addedCodes { val := rawdb.ReadCode(dstDb, node) rawdb.DeleteCode(dstDb, node) - if err := checkStateConsistency(dstDb, srcRoot); err == nil { + if err := checkStateConsistency(dstDb, ndb.Scheme(), srcRoot); err == nil { t.Errorf("trie inconsistency not caught, missing: %x", node) } rawdb.WriteCode(dstDb, node, val) } - scheme := srcDb.TrieDB().Scheme() for i, path := range addedPaths { owner, inner := trie.ResolvePath([]byte(path)) hash := addedHashes[i] @@ -668,9 +726,21 @@ func TestIncompleteStateSync(t *testing.T) { t.Error("missing trie node") } rawdb.DeleteTrieNode(dstDb, owner, inner, hash, scheme) - if err := checkStateConsistency(dstDb, srcRoot); err == nil { + if err := checkStateConsistency(dstDb, scheme, srcRoot); err == nil { t.Errorf("trie inconsistency not caught, missing: %v", path) } rawdb.WriteTrieNode(dstDb, owner, inner, hash, val, scheme) } } + +func copyPreimages(srcDb, dstDb ethdb.Database) { + it := srcDb.NewIterator(rawdb.PreimagePrefix, nil) + defer it.Release() + + preimages := make(map[common.Hash][]byte) + for it.Next() { + hash := it.Key()[len(rawdb.PreimagePrefix):] + preimages[common.BytesToHash(hash)] = common.CopyBytes(it.Value()) + } + rawdb.WritePreimages(dstDb, preimages) +} diff --git a/core/state/trie_prefetcher.go b/core/state/trie_prefetcher.go index 844f72fc10..4e8fd1e10f 100644 --- a/core/state/trie_prefetcher.go +++ b/core/state/trie_prefetcher.go @@ -302,7 +302,7 @@ func (sf *subfetcher) loop() { } sf.trie = trie } else { - trie, err := sf.db.OpenStorageTrie(sf.state, sf.owner, sf.root) + trie, err := sf.db.OpenStorageTrie(sf.state, sf.addr, sf.root) if err != nil { log.Warn("Trie prefetcher failed opening trie", "root", sf.root, "err", err) return diff --git a/core/state_processor.go b/core/state_processor.go index 25266f13b4..6a208a1811 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -17,12 +17,14 @@ package core import ( + "errors" "fmt" "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/consensus/misc/eip4844" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" @@ -75,6 +77,9 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vmenv = vm.NewEVM(context, vm.TxContext{}, statedb, p.config, cfg) signer = types.MakeSigner(p.config, header.Number, header.Time) ) + if beaconRoot := block.BeaconRoot(); beaconRoot != nil { + ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb) + } // Iterate over and process the individual transactions for i, tx := range block.Transactions() { msg, err := TransactionToMessage(tx, signer, header.BaseFee) @@ -91,8 +96,8 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg } // Fail if Shanghai not enabled and len(withdrawals) is non-zero. withdrawals := block.Withdrawals() - if len(withdrawals) > 0 && !p.config.IsShanghai(block.Time()) { - return nil, nil, 0, fmt.Errorf("withdrawals before shanghai") + 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.engine.Finalize(p.bc, header, statedb, block.Transactions(), block.Uncles(), withdrawals) @@ -131,6 +136,11 @@ func applyTransaction(msg *Message, config *params.ChainConfig, gp *GasPool, sta receipt.TxHash = tx.Hash() receipt.GasUsed = result.UsedGas + if tx.Type() == types.BlobTxType { + receipt.BlobGasUsed = uint64(len(tx.BlobHashes()) * params.BlobTxBlobGasPerBlob) + receipt.BlobGasPrice = eip4844.CalcBlobFee(*evm.Context.ExcessBlobGas) + } + // If the transaction created a contract, store the creation address in the receipt. if msg.To == nil { receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce()) @@ -156,6 +166,26 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo } // Create a new context to be used in the EVM environment blockContext := NewEVMBlockContext(header, bc, author) - vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, config, cfg) + vmenv := vm.NewEVM(blockContext, vm.TxContext{BlobHashes: tx.BlobHashes()}, statedb, config, cfg) return applyTransaction(msg, config, gp, statedb, header.Number, header.Hash(), tx, usedGas, vmenv) } + +// 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 EIP-4788 is enabled, we need to invoke the beaconroot storage contract with + // the new root + msg := &Message{ + From: params.SystemAddress, + GasLimit: 30_000_000, + GasPrice: common.Big0, + GasFeeCap: common.Big0, + GasTipCap: common.Big0, + To: ¶ms.BeaconRootsStorageAddress, + Data: beaconRoot[:], + } + vmenv.Reset(NewEVMTxContext(msg), statedb) + statedb.AddAddressToAccessList(params.BeaconRootsStorageAddress) + _, _, _ = vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.Big0) + statedb.Finalise(true) +} diff --git a/core/state_processor_test.go b/core/state_processor_test.go index 59391fa861..aade2f6d73 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -26,13 +26,15 @@ import ( "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/consensus/misc" + "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/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/trie" + "github.com/holiman/uint256" "golang.org/x/crypto/sha3" ) @@ -45,19 +47,23 @@ func u64(val uint64) *uint64 { return &val } func TestStateProcessorErrors(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), + 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), + TerminalTotalDifficulty: big.NewInt(0), + TerminalTotalDifficultyPassed: true, + ShanghaiTime: new(uint64), + CancunTime: new(uint64), } signer = types.LatestSigner(config) key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") @@ -89,6 +95,22 @@ func TestStateProcessorErrors(t *testing.T) { }), signer, key1) return tx } + var mkBlobTx = func(nonce uint64, to common.Address, gasLimit uint64, gasTipCap, gasFeeCap *big.Int, hashes []common.Hash) *types.Transaction { + tx, err := types.SignTx(types.NewTx(&types.BlobTx{ + Nonce: nonce, + GasTipCap: uint256.MustFromBig(gasTipCap), + GasFeeCap: uint256.MustFromBig(gasFeeCap), + Gas: gasLimit, + To: to, + BlobHashes: hashes, + Value: new(uint256.Int), + }), signer, key1) + if err != nil { + t.Fatal(err) + } + return tx + } + { // Tests against a 'recent' chain definition var ( db = rawdb.NewMemoryDatabase() @@ -105,8 +127,10 @@ func TestStateProcessorErrors(t *testing.T) { }, }, } - blockchain, _ = NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ = NewBlockChain(db, nil, gspec, nil, beacon.New(ethash.NewFaker()), vm.Config{}, nil, nil) + tooBigInitCode = [params.MaxInitCodeSize + 1]byte{} ) + defer blockchain.Stop() bigNumber := new(big.Int).SetBytes(common.FromHex("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")) tooBigNumber := new(big.Int).Set(bigNumber) @@ -209,8 +233,26 @@ func TestStateProcessorErrors(t *testing.T) { }, want: "could not apply tx 0 [0xd82a0c2519acfeac9a948258c47e784acd20651d9d80f9a1c67b4137651c3a24]: insufficient funds for gas * price + value: address 0x71562b71999873DB5b286dF957af199Ec94617F7 have 1000000000000000000 want 2431633873983640103894990685182446064918669677978451844828609264166175722438635000", }, + { // ErrMaxInitCodeSizeExceeded + txs: []*types.Transaction{ + mkDynamicCreationTx(0, 500000, common.Big0, big.NewInt(params.InitialBaseFee), tooBigInitCode[:]), + }, + want: "could not apply tx 0 [0xd491405f06c92d118dd3208376fcee18a57c54bc52063ee4a26b1cf296857c25]: max initcode size exceeded: code size 49153 limit 49152", + }, + { // ErrIntrinsicGas: Not enough gas to cover init code + txs: []*types.Transaction{ + mkDynamicCreationTx(0, 54299, common.Big0, big.NewInt(params.InitialBaseFee), make([]byte, 320)), + }, + want: "could not apply tx 0 [0xfd49536a9b323769d8472fcb3ebb3689b707a349379baee3e2ee3fe7baae06a1]: intrinsic gas too low: have 54299, want 54300", + }, + { // ErrBlobFeeCapTooLow + txs: []*types.Transaction{ + mkBlobTx(0, common.Address{}, params.TxGas, big.NewInt(1), big.NewInt(1), []common.Hash{(common.Hash{1})}), + }, + want: "could not apply tx 0 [0x6c11015985ce82db691d7b2d017acda296db88b811c3c60dc71449c76256c716]: max fee per gas less than block base fee: address 0x71562b71999873DB5b286dF957af199Ec94617F7, maxFeePerGas: 1 baseFee: 875000000", + }, } { - block := GenerateBadBlock(gspec.ToBlock(), ethash.NewFaker(), tt.txs, gspec.Config) + block := GenerateBadBlock(gspec.ToBlock(), beacon.New(ethash.NewFaker()), tt.txs, gspec.Config) _, err := blockchain.InsertChain(types.Blocks{block}) if err == nil { t.Fatal("block imported without errors") @@ -284,7 +326,7 @@ func TestStateProcessorErrors(t *testing.T) { }, }, } - blockchain, _ = NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ = NewBlockChain(db, nil, gspec, nil, beacon.New(ethash.NewFaker()), vm.Config{}, nil, nil) ) defer blockchain.Stop() for i, tt := range []struct { @@ -298,73 +340,7 @@ func TestStateProcessorErrors(t *testing.T) { want: "could not apply tx 0 [0x88626ac0d53cb65308f2416103c62bb1f18b805573d4f96a3640bbbfff13c14f]: sender not an eoa: address 0x71562b71999873DB5b286dF957af199Ec94617F7, codehash: 0x9280914443471259d4570a8661015ae4a5b80186dbc619658fb494bebc3da3d1", }, } { - block := GenerateBadBlock(gspec.ToBlock(), ethash.NewFaker(), tt.txs, gspec.Config) - _, err := blockchain.InsertChain(types.Blocks{block}) - if err == nil { - t.Fatal("block imported without errors") - } - if have, want := err.Error(), tt.want; have != want { - t.Errorf("test %d:\nhave \"%v\"\nwant \"%v\"\n", i, have, want) - } - } - } - - // ErrMaxInitCodeSizeExceeded, for this we need extra Shanghai (EIP-3860) enabled. - { - var ( - db = rawdb.NewMemoryDatabase() - gspec = &Genesis{ - 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), - ArrowGlacierBlock: big.NewInt(0), - GrayGlacierBlock: big.NewInt(0), - MergeNetsplitBlock: big.NewInt(0), - TerminalTotalDifficulty: big.NewInt(0), - TerminalTotalDifficultyPassed: true, - ShanghaiTime: u64(0), - }, - Alloc: GenesisAlloc{ - common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7"): GenesisAccount{ - Balance: big.NewInt(1000000000000000000), // 1 ether - Nonce: 0, - }, - }, - } - genesis = gspec.MustCommit(db) - blockchain, _ = NewBlockChain(db, nil, gspec, nil, beacon.New(ethash.NewFaker()), vm.Config{}, nil, nil) - tooBigInitCode = [params.MaxInitCodeSize + 1]byte{} - smallInitCode = [320]byte{} - ) - defer blockchain.Stop() - for i, tt := range []struct { - txs []*types.Transaction - want string - }{ - { // ErrMaxInitCodeSizeExceeded - txs: []*types.Transaction{ - mkDynamicCreationTx(0, 500000, common.Big0, misc.CalcBaseFee(config, genesis.Header()), tooBigInitCode[:]), - }, - want: "could not apply tx 0 [0x832b54a6c3359474a9f504b1003b2cc1b6fcaa18e4ef369eb45b5d40dad6378f]: max initcode size exceeded: code size 49153 limit 49152", - }, - { // ErrIntrinsicGas: Not enough gas to cover init code - txs: []*types.Transaction{ - mkDynamicCreationTx(0, 54299, common.Big0, misc.CalcBaseFee(config, genesis.Header()), smallInitCode[:]), - }, - want: "could not apply tx 0 [0x39b7436cb432d3662a25626474282c5c4c1a213326fd87e4e18a91477bae98b2]: intrinsic gas too low: have 54299, want 54300", - }, - } { - block := GenerateBadBlock(genesis, beacon.New(ethash.NewFaker()), tt.txs, gspec.Config) + block := GenerateBadBlock(gspec.ToBlock(), beacon.New(ethash.NewFaker()), tt.txs, gspec.Config) _, err := blockchain.InsertChain(types.Blocks{block}) if err == nil { t.Fatal("block imported without errors") @@ -401,9 +377,9 @@ func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Tr UncleHash: types.EmptyUncleHash, } if config.IsLondon(header.Number) { - header.BaseFee = misc.CalcBaseFee(config, parent.Header()) + header.BaseFee = eip1559.CalcBaseFee(config, parent.Header()) } - if config.IsShanghai(header.Time) { + if config.IsShanghai(header.Number, header.Time) { header.WithdrawalsHash = &types.EmptyWithdrawalsHash } var receipts []*types.Receipt @@ -412,6 +388,7 @@ func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Tr hasher := sha3.NewLegacyKeccak256() hasher.Write(header.Number.Bytes()) var cumulativeGas uint64 + var nBlobs int for _, tx := range txs { txh := tx.Hash() hasher.Write(txh[:]) @@ -420,10 +397,25 @@ func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Tr receipt.GasUsed = tx.Gas() receipts = append(receipts, receipt) cumulativeGas += tx.Gas() + nBlobs += len(tx.BlobHashes()) } header.Root = common.BytesToHash(hasher.Sum(nil)) + if config.IsCancun(header.Number, header.Time) { + var pExcess, pUsed = uint64(0), uint64(0) + if parent.ExcessBlobGas() != nil { + pExcess = *parent.ExcessBlobGas() + pUsed = *parent.BlobGasUsed() + } + excess := eip4844.CalcExcessBlobGas(pExcess, pUsed) + used := uint64(nBlobs * params.BlobTxBlobGasPerBlob) + header.ExcessBlobGas = &excess + header.BlobGasUsed = &used + + beaconRoot := common.HexToHash("0xbeac00") + header.ParentBeaconRoot = &beaconRoot + } // Assemble and return the final block for sealing - if config.IsShanghai(header.Time) { + if config.IsShanghai(header.Number, header.Time) { return types.NewBlockWithWithdrawals(header, txs, nil, receipts, []*types.Withdrawal{}, trie.NewStackTrie(nil)) } return types.NewBlock(header, txs, nil, receipts, trie.NewStackTrie(nil)) diff --git a/core/state_transition.go b/core/state_transition.go index 72f975775c..f84757be78 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -17,12 +17,14 @@ package core import ( + "errors" "fmt" "math" "math/big" "github.com/ethereum/go-ethereum/common" cmath "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/consensus/misc/eip4844" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/params" @@ -125,16 +127,18 @@ func toWordSize(size uint64) uint64 { // A Message contains the data derived from a single transaction that is relevant to state // processing. type Message struct { - To *common.Address - From common.Address - Nonce uint64 - Value *big.Int - GasLimit uint64 - GasPrice *big.Int - GasFeeCap *big.Int - GasTipCap *big.Int - Data []byte - AccessList types.AccessList + To *common.Address + From common.Address + Nonce uint64 + Value *big.Int + GasLimit uint64 + GasPrice *big.Int + GasFeeCap *big.Int + GasTipCap *big.Int + Data []byte + AccessList types.AccessList + 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. @@ -155,6 +159,8 @@ func TransactionToMessage(tx *types.Transaction, s types.Signer, baseFee *big.In Data: tx.Data(), AccessList: tx.AccessList(), SkipAccountChecks: false, + BlobHashes: tx.BlobHashes(), + BlobGasFeeCap: tx.BlobGasFeeCap(), } // If baseFee provided, set gasPrice to effectiveGasPrice. if baseFee != nil { @@ -228,12 +234,24 @@ 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) - balanceCheck := mgval + balanceCheck := new(big.Int).Set(mgval) if st.msg.GasFeeCap != nil { - balanceCheck = new(big.Int).SetUint64(st.msg.GasLimit) + balanceCheck.SetUint64(st.msg.GasLimit) balanceCheck = balanceCheck.Mul(balanceCheck, st.msg.GasFeeCap) 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 + blobBalanceCheck := new(big.Int).SetUint64(blobGas) + blobBalanceCheck.Mul(blobBalanceCheck, st.msg.BlobGasFeeCap) + balanceCheck.Add(balanceCheck, blobBalanceCheck) + // Pay for blobGasUsed * actual blob fee + blobFee := new(big.Int).SetUint64(blobGas) + blobFee.Mul(blobFee, eip4844.CalcBlobFee(*st.evm.Context.ExcessBlobGas)) + mgval.Add(mgval, blobFee) + } + } if have, want := st.state.GetBalance(st.msg.From), balanceCheck; have.Cmp(want) < 0 { return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientFunds, st.msg.From.Hex(), have, want) } @@ -295,6 +313,29 @@ func (st *StateTransition) preCheck() error { } } } + // Check the blob version validity + if msg.BlobHashes != nil { + if len(msg.BlobHashes) == 0 { + return errors.New("blob transaction missing blob hashes") + } + for i, hash := range msg.BlobHashes { + if hash[0] != params.BlobTxHashVersion { + return fmt.Errorf("blob %d hash version mismatch (have %d, supported %d)", + i, hash[0], params.BlobTxHashVersion) + } + } + } + + if st.evm.ChainConfig().IsCancun(st.evm.Context.BlockNumber, st.evm.Context.Time) { + if st.blobGasUsed() > 0 { + // Check that the user is paying at least the current blob fee + blobFee := eip4844.CalcBlobFee(*st.evm.Context.ExcessBlobGas) + if st.msg.BlobGasFeeCap.Cmp(blobFee) < 0 { + return fmt.Errorf("%w: address %v have %v want %v", ErrBlobFeeCapTooLow, st.msg.From.Hex(), st.msg.BlobGasFeeCap, blobFee) + } + } + } + return st.buyGas() } @@ -425,3 +466,8 @@ func (st *StateTransition) refundGas(refundQuotient uint64) { func (st *StateTransition) gasUsed() uint64 { return st.initialGas - st.gasRemaining } + +// blobGasUsed returns the amount of blob gas used by the message. +func (st *StateTransition) blobGasUsed() uint64 { + return uint64(len(st.msg.BlobHashes) * params.BlobTxBlobGasPerBlob) +} diff --git a/core/txpool/blobpool/blobpool.go b/core/txpool/blobpool/blobpool.go new file mode 100644 index 0000000000..042ff3be20 --- /dev/null +++ b/core/txpool/blobpool/blobpool.go @@ -0,0 +1,1528 @@ +// 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 blobpool implements the EIP-4844 blob transaction pool. +package blobpool + +import ( + "container/heap" + "errors" + "fmt" + "math" + "math/big" + "os" + "path/filepath" + "sort" + "sync" + "time" + + "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" + "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/event" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/metrics" + "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rlp" + "github.com/holiman/billy" + "github.com/holiman/uint256" +) + +const ( + // blobSize is the protocol constrained byte size of a single blob in a + // transaction. There can be multiple of these embedded into a single tx. + blobSize = params.BlobTxFieldElementsPerBlob * params.BlobTxBytesPerFieldElement + + // maxBlobsPerTransaction is the maximum number of blobs a single transaction + // is allowed to contain. Whilst the spec states it's unlimited, the block + // data slots are protocol bound, which implicitly also limit this. + maxBlobsPerTransaction = params.MaxBlobGasPerBlock / params.BlobTxBlobGasPerBlob + + // txAvgSize is an approximate byte size of a transaction metadata to avoid + // tiny overflows causing all txs to move a shelf higher, wasting disk space. + txAvgSize = 4 * 1024 + + // txMaxSize is the maximum size a single transaction can have, outside + // the included blobs. Since blob transactions are pulled instead of pushed, + // and only a small metadata is kept in ram, the rest is on disk, there is + // no critical limit that should be enforced. Still, capping it to some sane + // limit can never hurt. + txMaxSize = 1024 * 1024 + + // maxTxsPerAccount is the maximum number of blob transactions admitted from + // a single account. The limit is enforced to minimize the DoS potential of + // a private tx cancelling publicly propagated blobs. + // + // Note, transactions resurrected by a reorg are also subject to this limit, + // so pushing it down too aggressively might make resurrections non-functional. + maxTxsPerAccount = 16 + + // pendingTransactionStore is the subfolder containing the currently queued + // blob transactions. + pendingTransactionStore = "queue" + + // limboedTransactionStore is the subfolder containing the currently included + // but not yet finalized transaction blobs. + limboedTransactionStore = "limbo" +) + +// blobTxMeta is the minimal subset of types.BlobTx necessary to validate and +// schedule the blob transactions into the following blocks. Only ever add the +// bare minimum needed fields to keep the size down (and thus number of entries +// larger with the same memory consumption). +type blobTxMeta struct { + hash common.Hash // Transaction hash to maintain the lookup table + id uint64 // Storage ID in the pool's persistent store + size uint32 // Byte size in the pool's persistent store + + nonce uint64 // Needed to prioritize inclusion order within an account + costCap *uint256.Int // Needed to validate cumulative balance sufficiency + execTipCap *uint256.Int // Needed to prioritize inclusion order across accounts and validate replacement price bump + execFeeCap *uint256.Int // Needed to validate replacement price bump + blobFeeCap *uint256.Int // Needed to validate replacement price bump + + basefeeJumps float64 // Absolute number of 1559 fee adjustments needed to reach the tx's fee cap + blobfeeJumps float64 // Absolute number of 4844 fee adjustments needed to reach the tx's blob fee cap + + evictionExecTip *uint256.Int // Worst gas tip across all previous nonces + evictionExecFeeJumps float64 // Worst base fee (converted to fee jumps) across all previous nonces + evictionBlobFeeJumps float64 // Worse blob fee (converted to fee jumps) across all previous nonces +} + +// newBlobTxMeta retrieves the indexed metadata fields from a blob transaction +// and assembles a helper struct to track in memory. +func newBlobTxMeta(id uint64, size uint32, tx *types.Transaction) *blobTxMeta { + meta := &blobTxMeta{ + hash: tx.Hash(), + id: id, + size: size, + nonce: tx.Nonce(), + costCap: uint256.MustFromBig(tx.Cost()), + execTipCap: uint256.MustFromBig(tx.GasTipCap()), + execFeeCap: uint256.MustFromBig(tx.GasFeeCap()), + blobFeeCap: uint256.MustFromBig(tx.BlobGasFeeCap()), + } + meta.basefeeJumps = dynamicFeeJumps(meta.execFeeCap) + meta.blobfeeJumps = dynamicFeeJumps(meta.blobFeeCap) + + return meta +} + +// BlobPool is the transaction pool dedicated to EIP-4844 blob transactions. +// +// Blob transactions are special snowflakes that are designed for a very specific +// purpose (rollups) and are expected to adhere to that specific use case. These +// behavioural expectations allow us to design a transaction pool that is more robust +// (i.e. resending issues) and more resilient to DoS attacks (e.g. replace-flush +// attacks) than the generic tx pool. These improvements will also mean, however, +// that we enforce a significantly more aggressive strategy on entering and exiting +// the pool: +// +// - Blob transactions are large. With the initial design aiming for 128KB blobs, +// we must ensure that these only traverse the network the absolute minimum +// number of times. Broadcasting to sqrt(peers) is out of the question, rather +// these should only ever be announced and the remote side should request it if +// it wants to. +// +// - Block blob-space is limited. With blocks being capped to a few blob txs, we +// can make use of the very low expected churn rate within the pool. Notably, +// we should be able to use a persistent disk backend for the pool, solving +// the tx resend issue that plagues the generic tx pool, as long as there's no +// artificial churn (i.e. pool wars). +// +// - Purpose of blobs are layer-2s. Layer-2s are meant to use blob transactions to +// commit to their own current state, which is independent of Ethereum mainnet +// (state, txs). This means that there's no reason for blob tx cancellation or +// replacement, apart from a potential basefee / miner tip adjustment. +// +// - Replacements are expensive. Given their size, propagating a replacement +// blob transaction to an existing one should be aggressively discouraged. +// Whilst generic transactions can start at 1 Wei gas cost and require a 10% +// fee bump to replace, we suggest requiring a higher min cost (e.g. 1 gwei) +// and a more aggressive bump (100%). +// +// - Cancellation is prohibitive. Evicting an already propagated blob tx is a huge +// DoS vector. As such, a) replacement (higher-fee) blob txs mustn't invalidate +// already propagated (future) blob txs (cumulative fee); b) nonce-gapped blob +// txs are disallowed; c) the presence of blob transactions exclude non-blob +// transactions. +// +// - Malicious cancellations are possible. Although the pool might prevent txs +// that cancel blobs, blocks might contain such transaction (malicious miner +// or flashbotter). The pool should cap the total number of blob transactions +// per account as to prevent propagating too much data before cancelling it +// via a normal transaction. It should nonetheless be high enough to support +// resurrecting reorged transactions. Perhaps 4-16. +// +// - Local txs are meaningless. Mining pools historically used local transactions +// for payouts or for backdoor deals. With 1559 in place, the basefee usually +// dominates the final price, so 0 or non-0 tip doesn't change much. Blob txs +// retain the 1559 2D gas pricing (and introduce on top a dynamic blob gas fee), +// so locality is moot. With a disk backed blob pool avoiding the resend issue, +// there's also no need to save own transactions for later. +// +// - No-blob blob-txs are bad. Theoretically there's no strong reason to disallow +// blob txs containing 0 blobs. In practice, admitting such txs into the pool +// breaks the low-churn invariant as blob constraints don't apply anymore. Even +// though we could accept blocks containing such txs, a reorg would require moving +// them back into the blob pool, which can break invariants. +// +// - Dropping blobs needs delay. When normal transactions are included, they +// are immediately evicted from the pool since they are contained in the +// including block. Blobs however are not included in the execution chain, +// so a mini reorg cannot re-pool "lost" blob transactions. To support reorgs, +// blobs are retained on disk until they are finalised. +// +// - Blobs can arrive via flashbots. Blocks might contain blob transactions we +// have never seen on the network. Since we cannot recover them from blocks +// either, the engine_newPayload needs to give them to us, and we cache them +// until finality to support reorgs without tx losses. +// +// Whilst some constraints above might sound overly aggressive, the general idea is +// that the blob pool should work robustly for its intended use case and whilst +// anyone is free to use blob transactions for arbitrary non-rollup use cases, +// they should not be allowed to run amok the network. +// +// Implementation wise there are a few interesting design choices: +// +// - Adding a transaction to the pool blocks until persisted to disk. This is +// viable because TPS is low (2-4 blobs per block initially, maybe 8-16 at +// peak), so natural churn is a couple MB per block. Replacements doing O(n) +// updates are forbidden and transaction propagation is pull based (i.e. no +// pileup of pending data). +// +// - When transactions are chosen for inclusion, the primary criteria is the +// signer tip (and having a basefee/data fee high enough of course). However, +// same-tip transactions will be split by their basefee/datafee, preferring +// those that are closer to the current network limits. The idea being that +// very relaxed ones can be included even if the fees go up, when the closer +// ones could already be invalid. +// +// When the pool eventually reaches saturation, some old transactions - that may +// never execute - will need to be evicted in favor of newer ones. The eviction +// strategy is quite complex: +// +// - Exceeding capacity evicts the highest-nonce of the account with the lowest +// paying blob transaction anywhere in the pooled nonce-sequence, as that tx +// would be executed the furthest in the future and is thus blocking anything +// after it. The smallest is deliberately not evicted to avoid a nonce-gap. +// +// - Analogously, if the pool is full, the consideration price of a new tx for +// evicting an old one is the smallest price in the entire nonce-sequence of +// the account. This avoids malicious users DoSing the pool with seemingly +// high paying transactions hidden behind a low-paying blocked one. +// +// - Since blob transactions have 3 price parameters: execution tip, execution +// fee cap and data fee cap, there's no singular parameter to create a total +// price ordering on. What's more, since the base fee and blob fee can move +// independently of one another, there's no pre-defined way to combine them +// into a stable order either. This leads to a multi-dimensional problem to +// solve after every block. +// +// - The first observation is that comparing 1559 base fees or 4844 blob fees +// needs to happen in the context of their dynamism. Since these fees jump +// up or down in ~1.125 multipliers (at max) across blocks, comparing fees +// in two transactions should be based on log1.125(fee) to eliminate noise. +// +// - The second observation is that the basefee and blobfee move independently, +// so there's no way to split mixed txs on their own (A has higher base fee, +// B has higher blob fee). Rather than look at the absolute fees, the useful +// metric is the max time it can take to exceed the transaction's fee caps. +// Specifically, we're interested in the number of jumps needed to go from +// the current fee to the transaction's cap: +// +// jumps = log1.125(txfee) - log1.125(basefee) +// +// - The third observation is that the base fee tends to hover around rather +// than swing wildly. The number of jumps needed from the current fee starts +// to get less relevant the higher it is. To remove the noise here too, the +// pool will use log(jumps) as the delta for comparing transactions. +// +// delta = sign(jumps) * log(abs(jumps)) +// +// - To establish a total order, we need to reduce the dimensionality of the +// two base fees (log jumps) to a single value. The interesting aspect from +// the pool's perspective is how fast will a tx get executable (fees going +// down, crossing the smaller negative jump counter) or non-executable (fees +// going up, crossing the smaller positive jump counter). As such, the pool +// cares only about the min of the two delta values for eviction priority. +// +// priority = min(delta-basefee, delta-blobfee) +// +// - The above very aggressive dimensionality and noise reduction should result +// in transaction being grouped into a small number of buckets, the further +// the fees the larger the buckets. This is good because it allows us to use +// the miner tip meaningfully as a splitter. +// +// - For the scenario where the pool does not contain non-executable blob txs +// anymore, it does not make sense to grant a later eviction priority to txs +// with high fee caps since it could enable pool wars. As such, any positive +// priority will be grouped together. +// +// priority = min(delta-basefee, delta-blobfee, 0) +// +// Optimisation tradeoffs: +// +// - Eviction relies on 3 fee minimums per account (exec tip, exec cap and blob +// cap). Maintaining these values across all transactions from the account is +// problematic as each transaction replacement or inclusion would require a +// rescan of all other transactions to recalculate the minimum. Instead, the +// pool maintains a rolling minimum across the nonce range. Updating all the +// minimums will need to be done only starting at the swapped in/out nonce +// and leading up to the first no-change. +type BlobPool struct { + config Config // Pool configuration + reserve txpool.AddressReserver // Address reserver to ensure exclusivity across subpools + + store billy.Database // Persistent data store for the tx metadata and blobs + stored uint64 // Useful data size of all transactions on disk + limbo *limbo // Persistent data store for the non-finalized blobs + + signer types.Signer // Transaction signer to use for sender recovery + chain BlockChain // Chain object to access the state through + + head *types.Header // Current head of the chain + state *state.StateDB // Current state at the head of the chain + gasTip *uint256.Int // Currently accepted minimum gas tip + + lookup map[common.Hash]uint64 // Lookup table mapping hashes to tx billy entries + index map[common.Address][]*blobTxMeta // Blob transactions grouped by accounts, sorted by nonce + spent map[common.Address]*uint256.Int // Expenditure tracking for individual accounts + evict *evictHeap // Heap of cheapest accounts for eviction when full + + eventFeed event.Feed // Event feed to send out new tx events on pool inclusion + eventScope event.SubscriptionScope // Event scope to track and mass unsubscribe on termination + + lock sync.RWMutex // Mutex protecting the pool during reorg handling +} + +// New creates a new blob transaction pool to gather, sort and filter inbound +// blob transactions from the network. +func New(config Config, chain BlockChain) *BlobPool { + // Sanitize the input to ensure no vulnerable gas prices are set + config = (&config).sanitize() + + // Create the transaction pool with its initial settings + return &BlobPool{ + config: config, + signer: types.LatestSigner(chain.Config()), + chain: chain, + lookup: make(map[common.Hash]uint64), + index: make(map[common.Address][]*blobTxMeta), + spent: make(map[common.Address]*uint256.Int), + } +} + +// Filter returns whether the given transaction can be consumed by the blob pool. +func (p *BlobPool) Filter(tx *types.Transaction) bool { + return tx.Type() == types.BlobTxType +} + +// Init sets the gas price needed to keep a transaction in the pool and the chain +// head to allow balance / nonce checks. The transaction journal will be loaded +// from disk and filtered based on the provided starting settings. +func (p *BlobPool) Init(gasTip *big.Int, head *types.Header, reserve txpool.AddressReserver) error { + p.reserve = reserve + + var ( + queuedir string + limbodir string + ) + if p.config.Datadir != "" { + queuedir = filepath.Join(p.config.Datadir, pendingTransactionStore) + if err := os.MkdirAll(queuedir, 0700); err != nil { + return err + } + limbodir = filepath.Join(p.config.Datadir, limboedTransactionStore) + if err := os.MkdirAll(limbodir, 0700); err != nil { + return err + } + } + state, err := p.chain.StateAt(head.Root) + if err != nil { + return err + } + p.head, p.state = head, state + + // Index all transactions on disk and delete anything inprocessable + var fails []uint64 + index := func(id uint64, size uint32, blob []byte) { + if p.parseTransaction(id, size, blob) != nil { + fails = append(fails, id) + } + } + store, err := billy.Open(billy.Options{Path: queuedir}, newSlotter(), index) + if err != nil { + return err + } + p.store = store + + if len(fails) > 0 { + log.Warn("Dropping invalidated blob transactions", "ids", fails) + for _, id := range fails { + if err := p.store.Delete(id); err != nil { + p.Close() + return err + } + } + } + // Sort the indexed transactions by nonce and delete anything gapped, create + // the eviction heap of anyone still standing + for addr := range p.index { + p.recheck(addr, nil) + } + var ( + basefee = uint256.MustFromBig(eip1559.CalcBaseFee(p.chain.Config(), p.head)) + blobfee = uint256.MustFromBig(big.NewInt(params.BlobTxMinBlobGasprice)) + ) + if p.head.ExcessBlobGas != nil { + blobfee = uint256.MustFromBig(eip4844.CalcBlobFee(*p.head.ExcessBlobGas)) + } + p.evict = newPriceHeap(basefee, blobfee, &p.index) + + // Pool initialized, attach the blob limbo to it to track blobs included + // recently but not yet finalized + p.limbo, err = newLimbo(limbodir) + if err != nil { + p.Close() + return err + } + // Set the configured gas tip, triggering a filtering of anything just loaded + basefeeGauge.Update(int64(basefee.Uint64())) + blobfeeGauge.Update(int64(blobfee.Uint64())) + + p.SetGasTip(gasTip) + + // Since the user might have modified their pool's capacity, evict anything + // above the current allowance + for p.stored > p.config.Datacap { + p.drop() + } + // Update the metrics and return the constructed pool + datacapGauge.Update(int64(p.config.Datacap)) + p.updateStorageMetrics() + return nil +} + +// Close closes down the underlying persistent store. +func (p *BlobPool) Close() error { + var errs []error + if err := p.limbo.Close(); err != nil { + errs = append(errs, err) + } + if err := p.store.Close(); err != nil { + errs = append(errs, err) + } + p.eventScope.Close() + + switch { + case errs == nil: + return nil + case len(errs) == 1: + return errs[0] + default: + return fmt.Errorf("%v", errs) + } +} + +// parseTransaction is a callback method on pool creation that gets called for +// each transaction on disk to create the in-memory metadata index. +func (p *BlobPool) parseTransaction(id uint64, size uint32, blob []byte) error { + tx := new(types.Transaction) + if err := rlp.DecodeBytes(blob, tx); err != nil { + // This path is impossible unless the disk data representation changes + // across restarts. For that ever unprobable case, recover gracefully + // by ignoring this data entry. + log.Error("Failed to decode blob pool entry", "id", id, "err", err) + return err + } + if tx.BlobTxSidecar() == nil { + log.Error("Missing sidecar in blob pool entry", "id", id, "hash", tx.Hash()) + return errors.New("missing blob sidecar") + } + + meta := newBlobTxMeta(id, size, tx) + + sender, err := p.signer.Sender(tx) + if err != nil { + // This path is impossible unless the signature validity changes across + // restarts. For that ever unprobable case, recover gracefully by ignoring + // this data entry. + log.Error("Failed to recover blob tx sender", "id", id, "hash", tx.Hash(), "err", err) + return err + } + if _, ok := p.index[sender]; !ok { + if err := p.reserve(sender, true); err != nil { + return err + } + p.index[sender] = []*blobTxMeta{} + p.spent[sender] = new(uint256.Int) + } + p.index[sender] = append(p.index[sender], meta) + p.spent[sender] = new(uint256.Int).Add(p.spent[sender], meta.costCap) + + p.lookup[meta.hash] = meta.id + p.stored += uint64(meta.size) + + return nil +} + +// recheck verifies the pool's content for a specific account and drops anything +// that does not fit anymore (dangling or filled nonce, overdraft). +func (p *BlobPool) recheck(addr common.Address, inclusions map[common.Hash]uint64) { + // Sort the transactions belonging to the account so reinjects can be simpler + txs := p.index[addr] + if inclusions != nil && txs == nil { // during reorgs, we might find new accounts + return + } + sort.Slice(txs, func(i, j int) bool { + return txs[i].nonce < txs[j].nonce + }) + // If there is a gap between the chain state and the blob pool, drop + // all the transactions as they are non-executable. Similarly, if the + // entire tx range was included, drop all. + var ( + next = p.state.GetNonce(addr) + gapped = txs[0].nonce > next + filled = txs[len(txs)-1].nonce < next + ) + if gapped || filled { + var ( + ids []uint64 + nonces []uint64 + ) + for i := 0; i < len(txs); i++ { + ids = append(ids, txs[i].id) + nonces = append(nonces, txs[i].nonce) + + p.stored -= uint64(txs[i].size) + delete(p.lookup, txs[i].hash) + + // Included transactions blobs need to be moved to the limbo + if filled && inclusions != nil { + p.offload(addr, txs[i].nonce, txs[i].id, inclusions) + } + } + delete(p.index, addr) + delete(p.spent, addr) + if inclusions != nil { // only during reorgs will the heap will be initialized + heap.Remove(p.evict, p.evict.index[addr]) + } + p.reserve(addr, false) + + if gapped { + log.Warn("Dropping dangling blob transactions", "from", addr, "missing", next, "drop", nonces, "ids", ids) + } else { + log.Trace("Dropping filled blob transactions", "from", addr, "filled", nonces, "ids", ids) + } + for _, id := range ids { + if err := p.store.Delete(id); err != nil { + log.Error("Failed to delete blob transaction", "from", addr, "id", id, "err", err) + } + } + return + } + // If there is overlap between the chain state and the blob pool, drop + // anything below the current state + if txs[0].nonce < next { + var ( + ids []uint64 + nonces []uint64 + ) + for txs[0].nonce < next { + ids = append(ids, txs[0].id) + nonces = append(nonces, txs[0].nonce) + + p.spent[addr] = new(uint256.Int).Sub(p.spent[addr], txs[0].costCap) + p.stored -= uint64(txs[0].size) + delete(p.lookup, txs[0].hash) + + // Included transactions blobs need to be moved to the limbo + if inclusions != nil { + p.offload(addr, txs[0].nonce, txs[0].id, inclusions) + } + txs = txs[1:] + } + log.Trace("Dropping overlapped blob transactions", "from", addr, "overlapped", nonces, "ids", ids, "left", len(txs)) + for _, id := range ids { + if err := p.store.Delete(id); err != nil { + log.Error("Failed to delete blob transaction", "from", addr, "id", id, "err", err) + } + } + p.index[addr] = txs + } + // Iterate over the transactions to initialize their eviction thresholds + // and to detect any nonce gaps + txs[0].evictionExecTip = txs[0].execTipCap + txs[0].evictionExecFeeJumps = txs[0].basefeeJumps + txs[0].evictionBlobFeeJumps = txs[0].blobfeeJumps + + for i := 1; i < len(txs); i++ { + // If there's no nonce gap, initialize the evicion thresholds as the + // minimum between the cumulative thresholds and the current tx fees + if txs[i].nonce == txs[i-1].nonce+1 { + txs[i].evictionExecTip = txs[i-1].evictionExecTip + if txs[i].evictionExecTip.Cmp(txs[i].execTipCap) > 0 { + txs[i].evictionExecTip = txs[i].execTipCap + } + txs[i].evictionExecFeeJumps = txs[i-1].evictionExecFeeJumps + if txs[i].evictionExecFeeJumps > txs[i].basefeeJumps { + txs[i].evictionExecFeeJumps = txs[i].basefeeJumps + } + txs[i].evictionBlobFeeJumps = txs[i-1].evictionBlobFeeJumps + if txs[i].evictionBlobFeeJumps > txs[i].blobfeeJumps { + txs[i].evictionBlobFeeJumps = txs[i].blobfeeJumps + } + continue + } + // Sanity check that there's no double nonce. This case would be a coding + // error, but better know about it + if txs[i].nonce == txs[i-1].nonce { + log.Error("Duplicate nonce blob transaction", "from", addr, "nonce", txs[i].nonce) + } + // Otherwise if there's a nonce gap evict all later transactions + var ( + ids []uint64 + nonces []uint64 + ) + for j := i; j < len(txs); j++ { + ids = append(ids, txs[j].id) + nonces = append(nonces, txs[j].nonce) + + p.spent[addr] = new(uint256.Int).Sub(p.spent[addr], txs[j].costCap) + p.stored -= uint64(txs[j].size) + delete(p.lookup, txs[j].hash) + } + txs = txs[:i] + + log.Error("Dropping gapped blob transactions", "from", addr, "missing", txs[i-1].nonce+1, "drop", nonces, "ids", ids) + for _, id := range ids { + if err := p.store.Delete(id); err != nil { + log.Error("Failed to delete blob transaction", "from", addr, "id", id, "err", err) + } + } + p.index[addr] = txs + break + } + // Ensure that there's no over-draft, this is expected to happen when some + // transactions get included without publishing on the network + var ( + balance = uint256.MustFromBig(p.state.GetBalance(addr)) + spent = p.spent[addr] + ) + if spent.Cmp(balance) > 0 { + // Evict the highest nonce transactions until the pending set falls under + // the account's available balance + var ( + ids []uint64 + nonces []uint64 + ) + for p.spent[addr].Cmp(balance) > 0 { + last := txs[len(txs)-1] + txs[len(txs)-1] = nil + txs = txs[:len(txs)-1] + + ids = append(ids, last.id) + nonces = append(nonces, last.nonce) + + p.spent[addr] = new(uint256.Int).Sub(p.spent[addr], last.costCap) + p.stored -= uint64(last.size) + delete(p.lookup, last.hash) + } + if len(txs) == 0 { + delete(p.index, addr) + delete(p.spent, addr) + if inclusions != nil { // only during reorgs will the heap will be initialized + heap.Remove(p.evict, p.evict.index[addr]) + } + p.reserve(addr, false) + } else { + p.index[addr] = txs + } + log.Warn("Dropping overdrafted blob transactions", "from", addr, "balance", balance, "spent", spent, "drop", nonces, "ids", ids) + for _, id := range ids { + if err := p.store.Delete(id); err != nil { + log.Error("Failed to delete blob transaction", "from", addr, "id", id, "err", err) + } + } + } + // Sanity check that no account can have more queued transactions than the + // DoS protection threshold. + if len(txs) > maxTxsPerAccount { + // Evict the highest nonce transactions until the pending set falls under + // the account's transaction cap + var ( + ids []uint64 + nonces []uint64 + ) + for len(txs) > maxTxsPerAccount { + last := txs[len(txs)-1] + txs[len(txs)-1] = nil + txs = txs[:len(txs)-1] + + ids = append(ids, last.id) + nonces = append(nonces, last.nonce) + + p.spent[addr] = new(uint256.Int).Sub(p.spent[addr], last.costCap) + p.stored -= uint64(last.size) + delete(p.lookup, last.hash) + } + p.index[addr] = txs + + log.Warn("Dropping overcapped blob transactions", "from", addr, "kept", len(txs), "drop", nonces, "ids", ids) + for _, id := range ids { + if err := p.store.Delete(id); err != nil { + log.Error("Failed to delete blob transaction", "from", addr, "id", id, "err", err) + } + } + } + // Included cheap transactions might have left the remaining ones better from + // an eviction point, fix any potential issues in the heap. + if _, ok := p.index[addr]; ok && inclusions != nil { + heap.Fix(p.evict, p.evict.index[addr]) + } +} + +// offload removes a tracked blob transaction from the pool and moves it into the +// limbo for tracking until finality. +// +// The method may log errors for various unexpcted scenarios but will not return +// any of it since there's no clear error case. Some errors may be due to coding +// issues, others caused by signers mining MEV stuff or swapping transactions. In +// all cases, the pool needs to continue operating. +func (p *BlobPool) offload(addr common.Address, nonce uint64, id uint64, inclusions map[common.Hash]uint64) { + data, err := p.store.Get(id) + if err != nil { + log.Error("Blobs missing for included transaction", "from", addr, "nonce", nonce, "id", id, "err", err) + return + } + var tx types.Transaction + if err = rlp.DecodeBytes(data, &tx); err != nil { + log.Error("Blobs corrupted for included transaction", "from", addr, "nonce", nonce, "id", id, "err", err) + return + } + block, ok := inclusions[tx.Hash()] + if !ok { + log.Warn("Blob transaction swapped out by signer", "from", addr, "nonce", nonce, "id", id) + return + } + if err := p.limbo.push(&tx, block); err != nil { + log.Warn("Failed to offload blob tx into limbo", "err", err) + return + } +} + +// Reset implements txpool.SubPool, allowing the blob pool's internal state to be +// kept in sync with the main transacion pool's internal state. +func (p *BlobPool) Reset(oldHead, newHead *types.Header) { + waitStart := time.Now() + p.lock.Lock() + resetwaitHist.Update(time.Since(waitStart).Nanoseconds()) + defer p.lock.Unlock() + + defer func(start time.Time) { + resettimeHist.Update(time.Since(start).Nanoseconds()) + }(time.Now()) + + statedb, err := p.chain.StateAt(newHead.Root) + if err != nil { + log.Error("Failed to reset blobpool state", "err", err) + return + } + p.head = newHead + p.state = statedb + + // Run the reorg between the old and new head and figure out which accounts + // need to be rechecked and which transactions need to be readded + if reinject, inclusions := p.reorg(oldHead, newHead); reinject != nil { + for addr, txs := range reinject { + // Blindly push all the lost transactions back into the pool + for _, tx := range txs { + p.reinject(addr, tx.Hash()) + } + // Recheck the account's pooled transactions to drop included and + // invalidated one + p.recheck(addr, inclusions) + } + } + // Flush out any blobs from limbo that are older than the latest finality + if p.chain.Config().IsCancun(p.head.Number, p.head.Time) { + p.limbo.finalize(p.chain.CurrentFinalBlock()) + } + // Reset the price heap for the new set of basefee/blobfee pairs + var ( + basefee = uint256.MustFromBig(eip1559.CalcBaseFee(p.chain.Config(), newHead)) + blobfee = uint256.MustFromBig(big.NewInt(params.BlobTxMinBlobGasprice)) + ) + if newHead.ExcessBlobGas != nil { + blobfee = uint256.MustFromBig(eip4844.CalcBlobFee(*newHead.ExcessBlobGas)) + } + p.evict.reinit(basefee, blobfee, false) + + basefeeGauge.Update(int64(basefee.Uint64())) + blobfeeGauge.Update(int64(blobfee.Uint64())) + p.updateStorageMetrics() +} + +// reorg assembles all the transactors and missing transactions between an old +// and new head to figure out which account's tx set needs to be rechecked and +// which transactions need to be requeued. +// +// The transactionblock inclusion infos are also returned to allow tracking any +// just-included blocks by block number in the limbo. +func (p *BlobPool) reorg(oldHead, newHead *types.Header) (map[common.Address][]*types.Transaction, map[common.Hash]uint64) { + // If the pool was not yet initialized, don't do anything + if oldHead == nil { + return nil, nil + } + // If the reorg is too deep, avoid doing it (will happen during snap sync) + oldNum := oldHead.Number.Uint64() + newNum := newHead.Number.Uint64() + + if depth := uint64(math.Abs(float64(oldNum) - float64(newNum))); depth > 64 { + return nil, nil + } + // Reorg seems shallow enough to pull in all transactions into memory + var ( + transactors = make(map[common.Address]struct{}) + discarded = make(map[common.Address][]*types.Transaction) + included = make(map[common.Address][]*types.Transaction) + inclusions = make(map[common.Hash]uint64) + + rem = p.chain.GetBlock(oldHead.Hash(), oldHead.Number.Uint64()) + add = p.chain.GetBlock(newHead.Hash(), newHead.Number.Uint64()) + ) + if add == nil { + // if the new head is nil, it means that something happened between + // the firing of newhead-event and _now_: most likely a + // reorg caused by sync-reversion or explicit sethead back to an + // earlier block. + log.Warn("Blobpool reset with missing new head", "number", newHead.Number, "hash", newHead.Hash()) + return nil, nil + } + if rem == nil { + // This can happen if a setHead is performed, where we simply discard + // the old head from the chain. If that is the case, we don't have the + // lost transactions anymore, and there's nothing to add. + if newNum >= oldNum { + // If we reorged to a same or higher number, then it's not a case + // of setHead + log.Warn("Blobpool reset with missing old head", + "old", oldHead.Hash(), "oldnum", oldNum, "new", newHead.Hash(), "newnum", newNum) + return nil, nil + } + // If the reorg ended up on a lower number, it's indicative of setHead + // being the cause + log.Debug("Skipping blobpool reset caused by setHead", + "old", oldHead.Hash(), "oldnum", oldNum, "new", newHead.Hash(), "newnum", newNum) + return nil, nil + } + // Both old and new blocks exist, traverse through the progression chain + // and accumulate the transactors and transactions + for rem.NumberU64() > add.NumberU64() { + for _, tx := range rem.Transactions() { + from, _ := p.signer.Sender(tx) + + discarded[from] = append(discarded[from], tx) + transactors[from] = struct{}{} + } + if rem = p.chain.GetBlock(rem.ParentHash(), rem.NumberU64()-1); rem == nil { + log.Error("Unrooted old chain seen by blobpool", "block", oldHead.Number, "hash", oldHead.Hash()) + return nil, nil + } + } + for add.NumberU64() > rem.NumberU64() { + for _, tx := range add.Transactions() { + from, _ := p.signer.Sender(tx) + + included[from] = append(included[from], tx) + inclusions[tx.Hash()] = add.NumberU64() + transactors[from] = struct{}{} + } + if add = p.chain.GetBlock(add.ParentHash(), add.NumberU64()-1); add == nil { + log.Error("Unrooted new chain seen by blobpool", "block", newHead.Number, "hash", newHead.Hash()) + return nil, nil + } + } + for rem.Hash() != add.Hash() { + for _, tx := range rem.Transactions() { + from, _ := p.signer.Sender(tx) + + discarded[from] = append(discarded[from], tx) + transactors[from] = struct{}{} + } + if rem = p.chain.GetBlock(rem.ParentHash(), rem.NumberU64()-1); rem == nil { + log.Error("Unrooted old chain seen by blobpool", "block", oldHead.Number, "hash", oldHead.Hash()) + return nil, nil + } + for _, tx := range add.Transactions() { + from, _ := p.signer.Sender(tx) + + included[from] = append(included[from], tx) + inclusions[tx.Hash()] = add.NumberU64() + transactors[from] = struct{}{} + } + if add = p.chain.GetBlock(add.ParentHash(), add.NumberU64()-1); add == nil { + log.Error("Unrooted new chain seen by blobpool", "block", newHead.Number, "hash", newHead.Hash()) + return nil, nil + } + } + // 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) + for addr := range transactors { + // Generate the set that was lost to reinject into the pool + lost := make([]*types.Transaction, 0, len(discarded[addr])) + for _, tx := range types.TxDifference(discarded[addr], included[addr]) { + if p.Filter(tx) { + lost = append(lost, tx) + } + } + 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]) { + if p.Filter(tx) { + p.limbo.update(tx.Hash(), inclusions[tx.Hash()]) + } + } + } + return reinject, inclusions +} + +// reinject blindly pushes a transaction previously included in the chain - and +// just reorged out - into the pool. The transaction is assumed valid (having +// been in the chain), thus the only validation needed is nonce sorting and over- +// draft checks after injection. +// +// Note, the method will not initialize the eviction cache values as those will +// be done once for all transactions belonging to an account after all individual +// transactions are injected back into the pool. +func (p *BlobPool) reinject(addr common.Address, txhash common.Hash) { + // Retrieve the associated blob from the limbo. Without the blobs, we cannot + // add the transaction back into the pool as it is not mineable. + tx, err := p.limbo.pull(txhash) + if err != nil { + log.Error("Blobs unavailable, dropping reorged tx", "err", err) + return + } + // TODO: seems like an easy optimization here would be getting the serialized tx + // from limbo instead of re-serializing it here. + + // Serialize the transaction back into the primary datastore. + blob, err := rlp.EncodeToBytes(tx) + if err != nil { + log.Error("Failed to encode transaction for storage", "hash", tx.Hash(), "err", err) + return + } + id, err := p.store.Put(blob) + if err != nil { + log.Error("Failed to write transaction into storage", "hash", tx.Hash(), "err", err) + return + } + + // Update the indixes and metrics + meta := newBlobTxMeta(id, p.store.Size(id), tx) + if _, ok := p.index[addr]; !ok { + if err := p.reserve(addr, true); err != nil { + log.Warn("Failed to reserve account for blob pool", "tx", tx.Hash(), "from", addr, "err", err) + return + } + p.index[addr] = []*blobTxMeta{meta} + p.spent[addr] = meta.costCap + p.evict.Push(addr) + } else { + p.index[addr] = append(p.index[addr], meta) + p.spent[addr] = new(uint256.Int).Add(p.spent[addr], meta.costCap) + } + p.lookup[meta.hash] = meta.id + p.stored += uint64(meta.size) +} + +// SetGasTip implements txpool.SubPool, allowing the blob pool's gas requirements +// to be kept in sync with the main transacion pool's gas requirements. +func (p *BlobPool) SetGasTip(tip *big.Int) { + p.lock.Lock() + defer p.lock.Unlock() + + // Store the new minimum gas tip + old := p.gasTip + p.gasTip = uint256.MustFromBig(tip) + + // 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) + 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() +} + +// 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 { + // Ensure the transaction adheres to basic pool filters (type, size, tip) and + // consensus rules + baseOpts := &txpool.ValidationOptions{ + Config: p.chain.Config(), + Accept: 1 << types.BlobTxType, + MaxSize: txMaxSize, + MinTip: p.gasTip.ToBig(), + } + if err := txpool.ValidateTransaction(tx, p.head, p.signer, baseOpts); err != nil { + return err + } + // Ensure the transaction adheres to the stateful pool filters (nonce, balance) + stateOpts := &txpool.ValidationOptionsWithState{ + State: p.state, + + FirstNonceGap: func(addr common.Address) uint64 { + // Nonce gaps are not permitted in the blob pool, the first gap will + // be the next nonce shifted by however many transactions we already + // have pooled. + return p.state.GetNonce(addr) + uint64(len(p.index[addr])) + }, + UsedAndLeftSlots: func(addr common.Address) (int, int) { + have := len(p.index[addr]) + if have >= maxTxsPerAccount { + return have, 0 + } + return have, maxTxsPerAccount - have + }, + ExistingExpenditure: func(addr common.Address) *big.Int { + if spent := p.spent[addr]; spent != nil { + return spent.ToBig() + } + return new(big.Int) + }, + 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 nil + }, + } + if err := txpool.ValidateTransactionWithState(tx, p.signer, stateOpts); err != nil { + return err + } + // If the transaction replaces an existing one, ensure that price bumps are + // adhered to. + var ( + from, _ = p.signer.Sender(tx) // already validated above + 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)] + 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) + case tx.GasTipCapIntCmp(prev.execTipCap.ToBig()) <= 0: + return fmt.Errorf("%w: new tx gas tip cap %v <= %v queued", txpool.ErrReplaceUnderpriced, tx.GasTipCap(), prev.execTipCap) + case tx.BlobGasFeeCapIntCmp(prev.blobFeeCap.ToBig()) <= 0: + return fmt.Errorf("%w: new tx blob gas fee cap %v <= %v queued", txpool.ErrReplaceUnderpriced, tx.BlobGasFeeCap(), prev.blobFeeCap) + } + var ( + multiplier = uint256.NewInt(100 + p.config.PriceBump) + onehundred = uint256.NewInt(100) + + minGasFeeCap = new(uint256.Int).Div(new(uint256.Int).Mul(multiplier, prev.execFeeCap), onehundred) + minGasTipCap = new(uint256.Int).Div(new(uint256.Int).Mul(multiplier, prev.execTipCap), onehundred) + minBlobGasFeeCap = new(uint256.Int).Div(new(uint256.Int).Mul(multiplier, prev.blobFeeCap), onehundred) + ) + 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) + 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) + 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 nil +} + +// Has returns an indicator whether subpool has a transaction cached with the +// given hash. +func (p *BlobPool) Has(hash common.Hash) bool { + p.lock.RLock() + defer p.lock.RUnlock() + + _, ok := p.lookup[hash] + return ok +} + +// Get returns a transaction if it is contained in the pool, or nil otherwise. +func (p *BlobPool) Get(hash common.Hash) *types.Transaction { + // Track the amount of time waiting to retrieve a fully resolved blob tx from + // the pool and the amount of time actually spent on pulling the data from disk. + getStart := time.Now() + p.lock.RLock() + getwaitHist.Update(time.Since(getStart).Nanoseconds()) + defer p.lock.RUnlock() + + defer func(start time.Time) { + gettimeHist.Update(time.Since(start).Nanoseconds()) + }(time.Now()) + + // Pull the blob from disk and return an assembled response + id, ok := p.lookup[hash] + if !ok { + return nil + } + data, err := p.store.Get(id) + if err != nil { + log.Error("Tracked blob transaction missing from store", "hash", hash, "id", id, "err", err) + return nil + } + item := new(types.Transaction) + if err = rlp.DecodeBytes(data, item); err != nil { + log.Error("Blobs corrupted for traced transaction", "hash", hash, "id", id, "err", err) + return nil + } + return item +} + +// Add inserts a set of blob transactions into the pool if they pass validation (both +// consensus validity and pool restictions). +func (p *BlobPool) Add(txs []*types.Transaction, local bool, sync bool) []error { + errs := make([]error, len(txs)) + for i, tx := range txs { + errs[i] = p.add(tx) + } + return errs +} + +// Add inserts a new blob transaction into the pool if it passes validation (both +// consensus validity and pool restictions). +func (p *BlobPool) add(tx *types.Transaction) (err error) { + // The blob pool blocks on adding a transaction. This is because blob txs are + // only even pulled form the network, so this method will act as the overload + // protection for fetches. + waitStart := time.Now() + p.lock.Lock() + addwaitHist.Update(time.Since(waitStart).Nanoseconds()) + defer p.lock.Unlock() + + defer func(start time.Time) { + addtimeHist.Update(time.Since(start).Nanoseconds()) + }(time.Now()) + + // Ensure the transaction is valid from all perspectives + if err := p.validateTx(tx); err != nil { + log.Trace("Transaction validation failed", "hash", tx.Hash(), "err", err) + return err + } + // If the address is not yet known, request exclusivity to track the account + // only by this subpool until all transactions are evicted + from, _ := types.Sender(p.signer, tx) // already validated above + if _, ok := p.index[from]; !ok { + if err := p.reserve(from, true); err != nil { + return err + } + defer func() { + // If the transaction is rejected by some post-validation check, remove + // the lock on the reservation set. + // + // Note, `err` here is the named error return, which will be initialized + // by a return statement before running deferred methods. Take care with + // removing or subscoping err as it will break this clause. + if err != nil { + p.reserve(from, false) + } + }() + } + // Transaction permitted into the pool from a nonce and cost perspective, + // insert it into the database and update the indices + blob, err := rlp.EncodeToBytes(tx) + if err != nil { + log.Error("Failed to encode transaction for storage", "hash", tx.Hash(), "err", err) + return err + } + id, err := p.store.Put(blob) + if err != nil { + return err + } + meta := newBlobTxMeta(id, p.store.Size(id), tx) + + var ( + next = p.state.GetNonce(from) + offset = int(tx.Nonce() - next) + newacc = false + ) + var oldEvictionExecFeeJumps, oldEvictionBlobFeeJumps float64 + if txs, ok := p.index[from]; ok { + oldEvictionExecFeeJumps = txs[len(txs)-1].evictionExecFeeJumps + oldEvictionBlobFeeJumps = txs[len(txs)-1].evictionBlobFeeJumps + } + if len(p.index[from]) > offset { + // Transaction replaces a previously queued one + prev := p.index[from][offset] + if err := p.store.Delete(prev.id); err != nil { + // Shitty situation, but try to recover gracefully instead of going boom + log.Error("Failed to delete replaced transaction", "id", prev.id, "err", err) + } + // Update the transaction index + p.index[from][offset] = meta + p.spent[from] = new(uint256.Int).Sub(p.spent[from], prev.costCap) + p.spent[from] = new(uint256.Int).Add(p.spent[from], meta.costCap) + + delete(p.lookup, prev.hash) + p.lookup[meta.hash] = meta.id + p.stored += uint64(meta.size) - uint64(prev.size) + } else { + // Transaction extends previously scheduled ones + p.index[from] = append(p.index[from], meta) + if _, ok := p.spent[from]; !ok { + p.spent[from] = new(uint256.Int) + newacc = true + } + p.spent[from] = new(uint256.Int).Add(p.spent[from], meta.costCap) + p.lookup[meta.hash] = meta.id + p.stored += uint64(meta.size) + } + // Recompute the rolling eviction fields. In case of a replacement, this will + // recompute all subsequent fields. In case of an append, this will only do + // the fresh calculation. + txs := p.index[from] + + for i := offset; i < len(txs); i++ { + // The first transaction will always use itself + if i == 0 { + txs[0].evictionExecTip = txs[0].execTipCap + txs[0].evictionExecFeeJumps = txs[0].basefeeJumps + txs[0].evictionBlobFeeJumps = txs[0].blobfeeJumps + + continue + } + // Subsequent transactions will use a rolling calculation + txs[i].evictionExecTip = txs[i-1].evictionExecTip + if txs[i].evictionExecTip.Cmp(txs[i].execTipCap) > 0 { + txs[i].evictionExecTip = txs[i].execTipCap + } + txs[i].evictionExecFeeJumps = txs[i-1].evictionExecFeeJumps + if txs[i].evictionExecFeeJumps > txs[i].basefeeJumps { + txs[i].evictionExecFeeJumps = txs[i].basefeeJumps + } + txs[i].evictionBlobFeeJumps = txs[i-1].evictionBlobFeeJumps + if txs[i].evictionBlobFeeJumps > txs[i].blobfeeJumps { + txs[i].evictionBlobFeeJumps = txs[i].blobfeeJumps + } + } + // Update the eviction heap with the new information: + // - If the transaction is from a new account, add it to the heap + // - If the account had a singleton tx replaced, update the heap (new price caps) + // - If the account has a transaction replaced or appended, update the heap if significantly changed + switch { + case newacc: + heap.Push(p.evict, from) + + case len(txs) == 1: // 1 tx and not a new acc, must be replacement + heap.Fix(p.evict, p.evict.index[from]) + + default: // replacement or new append + evictionExecFeeDiff := oldEvictionExecFeeJumps - txs[len(txs)-1].evictionExecFeeJumps + evictionBlobFeeDiff := oldEvictionBlobFeeJumps - txs[len(txs)-1].evictionBlobFeeJumps + + if math.Abs(evictionExecFeeDiff) > 0.001 || math.Abs(evictionBlobFeeDiff) > 0.001 { // need math.Abs, can go up and down + heap.Fix(p.evict, p.evict.index[from]) + } + } + // If the pool went over the allowed data limit, evict transactions until + // we're again below the threshold + for p.stored > p.config.Datacap { + p.drop() + } + p.updateStorageMetrics() + + return nil +} + +// drop removes the worst transaction from the pool. It is primarily used when a +// freshly added transaction overflows the pool and needs to evict something. The +// method is also called on startup if the user resizes their storage, might be an +// expensive run but it should be fine-ish. +func (p *BlobPool) drop() { + // Peek at the account with the worse transaction set to evict from (Go's heap + // stores the minimum at index zero of the heap slice) and retrieve it's last + // transaction. + var ( + from = p.evict.addrs[0] // cannot call drop on empty pool + + txs = p.index[from] + drop = txs[len(txs)-1] + last = len(txs) == 1 + ) + // Remove the transaction from the pool's index + if last { + delete(p.index, from) + delete(p.spent, from) + p.reserve(from, false) + } else { + txs[len(txs)-1] = nil + txs = txs[:len(txs)-1] + + p.index[from] = txs + p.spent[from] = new(uint256.Int).Sub(p.spent[from], drop.costCap) + } + p.stored -= uint64(drop.size) + delete(p.lookup, drop.hash) + + // Remove the transaction from the pool's evicion heap: + // - If the entire account was dropped, pop off the address + // - Otherwise, if the new tail has better eviction caps, fix the heap + if last { + heap.Pop(p.evict) + } else { + tail := txs[len(txs)-1] // new tail, surely exists + + evictionExecFeeDiff := tail.evictionExecFeeJumps - drop.evictionExecFeeJumps + evictionBlobFeeDiff := tail.evictionBlobFeeJumps - drop.evictionBlobFeeJumps + + if evictionExecFeeDiff > 0.001 || evictionBlobFeeDiff > 0.001 { // no need for math.Abs, monotonic decreasing + heap.Fix(p.evict, 0) + } + } + // Remove the transaction from the data store + log.Warn("Evicting overflown blob transaction", "from", from, "evicted", drop.nonce, "id", drop.id) + if err := p.store.Delete(drop.id); err != nil { + log.Error("Failed to drop evicted transaction", "id", drop.id, "err", err) + } +} + +// Pending retrieves all currently processable transactions, grouped by origin +// account and sorted by nonce. +func (p *BlobPool) Pending(enforceTips bool) map[common.Address][]*txpool.LazyTransaction { + // Track the amount of time waiting to retrieve the list of pending blob txs + // from the pool and the amount of time actually spent on assembling the data. + // The latter will be pretty much moot, but we've kept it to have symmetric + // across all user operations. + pendStart := time.Now() + p.lock.RLock() + pendwaitHist.Update(time.Since(pendStart).Nanoseconds()) + defer p.lock.RUnlock() + + defer func(start time.Time) { + pendtimeHist.Update(time.Since(start).Nanoseconds()) + }(time.Now()) + + pending := make(map[common.Address][]*txpool.LazyTransaction) + for addr, txs := range p.index { + var lazies []*txpool.LazyTransaction + for _, tx := range txs { + lazies = append(lazies, &txpool.LazyTransaction{ + Pool: p, + Hash: tx.hash, + Time: time.Now(), // TODO(karalabe): Maybe save these and use that? + GasFeeCap: tx.execFeeCap.ToBig(), + GasTipCap: tx.execTipCap.ToBig(), + }) + } + if len(lazies) > 0 { + pending[addr] = lazies + } + } + return pending +} + +// updateStorageMetrics retrieves a bunch of stats from the data store and pushes +// them out as metrics. +func (p *BlobPool) updateStorageMetrics() { + stats := p.store.Infos() + + var ( + dataused uint64 + datareal uint64 + slotused uint64 + + oversizedDataused uint64 + oversizedDatagaps uint64 + oversizedSlotused uint64 + oversizedSlotgaps uint64 + ) + for _, shelf := range stats.Shelves { + slotDataused := shelf.FilledSlots * uint64(shelf.SlotSize) + slotDatagaps := shelf.GappedSlots * uint64(shelf.SlotSize) + + dataused += slotDataused + datareal += slotDataused + slotDatagaps + slotused += shelf.FilledSlots + + metrics.GetOrRegisterGauge(fmt.Sprintf(shelfDatausedGaugeName, shelf.SlotSize/blobSize), nil).Update(int64(slotDataused)) + metrics.GetOrRegisterGauge(fmt.Sprintf(shelfDatagapsGaugeName, shelf.SlotSize/blobSize), nil).Update(int64(slotDatagaps)) + metrics.GetOrRegisterGauge(fmt.Sprintf(shelfSlotusedGaugeName, shelf.SlotSize/blobSize), nil).Update(int64(shelf.FilledSlots)) + metrics.GetOrRegisterGauge(fmt.Sprintf(shelfSlotgapsGaugeName, shelf.SlotSize/blobSize), nil).Update(int64(shelf.GappedSlots)) + + if shelf.SlotSize/blobSize > maxBlobsPerTransaction { + oversizedDataused += slotDataused + oversizedDatagaps += slotDatagaps + oversizedSlotused += shelf.FilledSlots + oversizedSlotgaps += shelf.GappedSlots + } + } + datausedGauge.Update(int64(dataused)) + datarealGauge.Update(int64(datareal)) + slotusedGauge.Update(int64(slotused)) + + oversizedDatausedGauge.Update(int64(oversizedDataused)) + oversizedDatagapsGauge.Update(int64(oversizedDatagaps)) + oversizedSlotusedGauge.Update(int64(oversizedSlotused)) + oversizedSlotgapsGauge.Update(int64(oversizedSlotgaps)) + + p.updateLimboMetrics() +} + +// updateLimboMetrics retrieves a bunch of stats from the limbo store and pushes +// // them out as metrics. +func (p *BlobPool) updateLimboMetrics() { + stats := p.limbo.store.Infos() + + var ( + dataused uint64 + datareal uint64 + slotused uint64 + ) + for _, shelf := range stats.Shelves { + slotDataused := shelf.FilledSlots * uint64(shelf.SlotSize) + slotDatagaps := shelf.GappedSlots * uint64(shelf.SlotSize) + + dataused += slotDataused + datareal += slotDataused + slotDatagaps + slotused += shelf.FilledSlots + + metrics.GetOrRegisterGauge(fmt.Sprintf(limboShelfDatausedGaugeName, shelf.SlotSize/blobSize), nil).Update(int64(slotDataused)) + metrics.GetOrRegisterGauge(fmt.Sprintf(limboShelfDatagapsGaugeName, shelf.SlotSize/blobSize), nil).Update(int64(slotDatagaps)) + metrics.GetOrRegisterGauge(fmt.Sprintf(limboShelfSlotusedGaugeName, shelf.SlotSize/blobSize), nil).Update(int64(shelf.FilledSlots)) + metrics.GetOrRegisterGauge(fmt.Sprintf(limboShelfSlotgapsGaugeName, shelf.SlotSize/blobSize), nil).Update(int64(shelf.GappedSlots)) + } + limboDatausedGauge.Update(int64(dataused)) + limboDatarealGauge.Update(int64(datareal)) + limboSlotusedGauge.Update(int64(slotused)) +} + +// SubscribeTransactions registers a subscription of NewTxsEvent and +// starts sending event to the given channel. +func (p *BlobPool) SubscribeTransactions(ch chan<- core.NewTxsEvent) event.Subscription { + return p.eventScope.Track(p.eventFeed.Subscribe(ch)) +} + +// 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() + + if txs, ok := p.index[addr]; ok { + return txs[len(txs)-1].nonce + 1 + } + return p.state.GetNonce(addr) +} + +// 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() + + var pending int + for _, txs := range p.index { + pending += len(txs) + } + return pending, 0 // No non-executable txs in the blob pool +} + +// Content retrieves the data content of the transaction pool, returning all the +// pending as well as queued transactions, grouped by account and sorted by nonce. +// +// For the blob pool, this method will return nothing for now. +// TODO(karalabe): Abstract out the returned metadata. +func (p *BlobPool) Content() (map[common.Address][]*types.Transaction, map[common.Address][]*types.Transaction) { + return make(map[common.Address][]*types.Transaction), make(map[common.Address][]*types.Transaction) +} + +// ContentFrom retrieves the data content of the transaction pool, returning the +// pending as well as queued transactions of this address, grouped by nonce. +// +// For the blob pool, this method will return nothing for now. +// TODO(karalabe): Abstract out the returned metadata. +func (p *BlobPool) ContentFrom(addr common.Address) ([]*types.Transaction, []*types.Transaction) { + return []*types.Transaction{}, []*types.Transaction{} +} + +// Locals retrieves the accounts currently considered local by the pool. +// +// There is no notion of local accounts in the blob pool. +func (p *BlobPool) Locals() []common.Address { + return []common.Address{} +} + +// Status returns the known status (unknown/pending/queued) of a transaction +// identified by their hashes. +func (p *BlobPool) Status(hash common.Hash) txpool.TxStatus { + if p.Has(hash) { + return txpool.TxStatusPending + } + return txpool.TxStatusUnknown +} diff --git a/core/txpool/blobpool/blobpool_test.go b/core/txpool/blobpool/blobpool_test.go new file mode 100644 index 0000000000..8914301e14 --- /dev/null +++ b/core/txpool/blobpool/blobpool_test.go @@ -0,0 +1,1251 @@ +// 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 blobpool + +import ( + "bytes" + "crypto/ecdsa" + "crypto/sha256" + "errors" + "math" + "math/big" + "os" + "path/filepath" + "sync" + "testing" + "time" + + "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" + "github.com/ethereum/go-ethereum/core/rawdb" + "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/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" + "github.com/holiman/billy" + "github.com/holiman/uint256" +) + +var ( + emptyBlob = kzg4844.Blob{} + emptyBlobCommit, _ = kzg4844.BlobToCommitment(emptyBlob) + emptyBlobProof, _ = kzg4844.ComputeBlobProof(emptyBlob, emptyBlobCommit) + emptyBlobVHash = blobHash(emptyBlobCommit) +) + +func blobHash(commit kzg4844.Commitment) common.Hash { + hasher := sha256.New() + hasher.Write(commit[:]) + hash := hasher.Sum(nil) + + var vhash common.Hash + vhash[0] = params.BlobTxHashVersion + copy(vhash[1:], hash[1:]) + + return vhash +} + +// 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 +} + +func (bc *testBlockChain) Config() *params.ChainConfig { + return bc.config +} + +func (bc *testBlockChain) CurrentBlock() *types.Header { + // Yolo, life is too short to invert mist.CalcBaseFee and misc.CalcBlobFee, + // just binary search it them. + + // The base fee at 5714 ETH translates into the 21000 base gas higher than + // mainnet ether existence, use that as a cap for the tests. + var ( + blockNumber = new(big.Int).Add(bc.config.LondonBlock, big.NewInt(1)) + blockTime = *bc.config.CancunTime + 1 + gasLimit = uint64(30_000_000) + ) + lo := new(big.Int) + hi := new(big.Int).Mul(big.NewInt(5714), new(big.Int).Exp(big.NewInt(10), big.NewInt(18), nil)) + + for new(big.Int).Add(lo, big.NewInt(1)).Cmp(hi) != 0 { + mid := new(big.Int).Add(lo, hi) + mid.Div(mid, big.NewInt(2)) + + if eip1559.CalcBaseFee(bc.config, &types.Header{ + Number: blockNumber, + GasLimit: gasLimit, + GasUsed: 0, + BaseFee: mid, + }).Cmp(bc.basefee.ToBig()) > 0 { + hi = mid + } else { + lo = mid + } + } + baseFee := lo + + // The excess blob gas at 2^27 translates into a blob fee higher than mainnet + // ether existence, use that as a cap for the tests. + lo = new(big.Int) + hi = new(big.Int).Exp(big.NewInt(2), big.NewInt(27), nil) + + for new(big.Int).Add(lo, big.NewInt(1)).Cmp(hi) != 0 { + mid := new(big.Int).Add(lo, hi) + mid.Div(mid, big.NewInt(2)) + + if eip4844.CalcBlobFee(mid.Uint64()).Cmp(bc.blobfee.ToBig()) > 0 { + hi = mid + } else { + lo = mid + } + } + excessBlobGas := lo.Uint64() + + return &types.Header{ + Number: blockNumber, + Time: blockTime, + GasLimit: gasLimit, + BaseFee: baseFee, + ExcessBlobGas: &excessBlobGas, + } +} + +func (bc *testBlockChain) CurrentFinalBlock() *types.Header { + return &types.Header{ + Number: big.NewInt(0), + } +} + +func (bt *testBlockChain) GetBlock(hash common.Hash, number uint64) *types.Block { + return nil +} + +func (bc *testBlockChain) StateAt(common.Hash) (*state.StateDB, error) { + return bc.statedb, nil +} + +// makeAddressReserver is a utility method to sanity check that accounts are +// properly reserved by the blobpool (no duplicate reserves or unreserves). +func makeAddressReserver() txpool.AddressReserver { + var ( + reserved = make(map[common.Address]struct{}) + lock sync.Mutex + ) + return func(addr common.Address, reserve bool) error { + lock.Lock() + defer lock.Unlock() + + _, exists := reserved[addr] + if reserve { + if exists { + panic("already reserved") + } + reserved[addr] = struct{}{} + return nil + } + if !exists { + panic("not reserved") + } + delete(reserved, addr) + return nil + } +} + +// makeTx is a utility method to construct a random blob transaction and sign it +// with a valid key, only setting the interesting fields from the perspective of +// 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) +} + +// makeUnsignedTx is a utility method to construct a random blob tranasaction +// without signing it. +func makeUnsignedTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCap uint64) *types.BlobTx { + return &types.BlobTx{ + ChainID: uint256.MustFromBig(testChainConfig.ChainID), + Nonce: nonce, + GasTipCap: uint256.NewInt(gasTipCap), + GasFeeCap: uint256.NewInt(gasFeeCap), + Gas: 21000, + BlobFeeCap: uint256.NewInt(blobFeeCap), + BlobHashes: []common.Hash{emptyBlobVHash}, + Value: uint256.NewInt(100), + Sidecar: &types.BlobTxSidecar{ + Blobs: []kzg4844.Blob{emptyBlob}, + Commitments: []kzg4844.Commitment{emptyBlobCommit}, + Proofs: []kzg4844.Proof{emptyBlobProof}, + }, + } +} + +// verifyPoolInternals iterates over all the transactions in the pool and checks +// that sort orders, calculated fields, cumulated fields are correct. +func verifyPoolInternals(t *testing.T, pool *BlobPool) { + // Mark this method as a helper to remove from stack traces + t.Helper() + + // Verify that all items in the index are present in the lookup and nothing more + seen := make(map[common.Hash]struct{}) + for addr, txs := range pool.index { + for _, tx := range txs { + if _, ok := seen[tx.hash]; ok { + t.Errorf("duplicate hash #%x in transaction index: address %s, nonce %d", tx.hash, addr, tx.nonce) + } + seen[tx.hash] = struct{}{} + } + } + for hash, id := range pool.lookup { + if _, ok := seen[hash]; !ok { + t.Errorf("lookup entry missing from transaction index: hash #%x, id %d", hash, id) + } + delete(seen, hash) + } + 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 + 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) + } + } + } + // Verify that calculated evacuation thresholds are correct + for addr, txs := range pool.index { + if !txs[0].evictionExecTip.Eq(txs[0].execTipCap) { + t.Errorf("addr %v, tx %d eviction execution tip mismatch: have %d, want %d", addr, 0, txs[0].evictionExecTip, txs[0].execTipCap) + } + if math.Abs(txs[0].evictionExecFeeJumps-txs[0].basefeeJumps) > 0.001 { + t.Errorf("addr %v, tx %d eviction execution fee jumps mismatch: have %f, want %f", addr, 0, txs[0].evictionExecFeeJumps, txs[0].basefeeJumps) + } + if math.Abs(txs[0].evictionBlobFeeJumps-txs[0].blobfeeJumps) > 0.001 { + t.Errorf("addr %v, tx %d eviction blob fee jumps mismatch: have %f, want %f", addr, 0, txs[0].evictionBlobFeeJumps, txs[0].blobfeeJumps) + } + for i := 1; i < len(txs); i++ { + wantExecTip := txs[i-1].evictionExecTip + if wantExecTip.Gt(txs[i].execTipCap) { + wantExecTip = txs[i].execTipCap + } + if !txs[i].evictionExecTip.Eq(wantExecTip) { + t.Errorf("addr %v, tx %d eviction execution tip mismatch: have %d, want %d", addr, i, txs[i].evictionExecTip, wantExecTip) + } + + wantExecFeeJumps := txs[i-1].evictionExecFeeJumps + if wantExecFeeJumps > txs[i].basefeeJumps { + wantExecFeeJumps = txs[i].basefeeJumps + } + if math.Abs(txs[i].evictionExecFeeJumps-wantExecFeeJumps) > 0.001 { + t.Errorf("addr %v, tx %d eviction execution fee jumps mismatch: have %f, want %f", addr, i, txs[i].evictionExecFeeJumps, wantExecFeeJumps) + } + + wantBlobFeeJumps := txs[i-1].evictionBlobFeeJumps + if wantBlobFeeJumps > txs[i].blobfeeJumps { + wantBlobFeeJumps = txs[i].blobfeeJumps + } + if math.Abs(txs[i].evictionBlobFeeJumps-wantBlobFeeJumps) > 0.001 { + t.Errorf("addr %v, tx %d eviction blob fee jumps mismatch: have %f, want %f", addr, i, txs[i].evictionBlobFeeJumps, wantBlobFeeJumps) + } + } + } + // Verify that account balance accumulations are correct + for addr, txs := range pool.index { + spent := new(uint256.Int) + for _, tx := range txs { + spent.Add(spent, tx.costCap) + } + if !pool.spent[addr].Eq(spent) { + t.Errorf("addr %v expenditure mismatch: have %d, want %d", addr, pool.spent[addr], spent) + } + } + // Verify that pool storage size is correct + var stored uint64 + for _, txs := range pool.index { + for _, tx := range txs { + stored += uint64(tx.size) + } + } + if pool.stored != stored { + t.Errorf("pool storage mismatch: have %d, want %d", pool.stored, stored) + } + // Verify the price heap internals + verifyHeapInternals(t, pool.evict) +} + +// Tests that transactions can be loaded from disk on startup and that they are +// correctly discarded if invalid. +// +// - 1. A transaction that cannot be decoded must be dropped +// - 2. A transaction that cannot be recovered (bad signature) must be dropped +// - 3. All transactions after a nonce gap must be dropped +// - 4. All transactions after an underpriced one (including it) must be dropped +func TestOpenDrops(t *testing.T) { + log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) + + // Create a temporary folder for the persistent backend + storage, _ := os.MkdirTemp("", "blobpool-") + defer os.RemoveAll(storage) + + os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700) + store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(), nil) + + // Insert a malformed transaction to verify that decoding errors (or format + // changes) are handled gracefully (case 1) + malformed, _ := store.Put([]byte("this is a badly encoded transaction")) + + // 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), + GasTipCap: new(uint256.Int), + GasFeeCap: new(uint256.Int), + Gas: 0, + Value: new(uint256.Int), + Data: nil, + BlobFeeCap: new(uint256.Int), + V: new(uint256.Int), + R: new(uint256.Int), + S: new(uint256.Int), + }) + blob, _ := rlp.EncodeToBytes(tx) + badsig, _ := store.Put(blob) + + // Insert a sequence of transactions with a nonce gap in between to verify + // that anything gapped will get evicted (case 3) + var ( + gapper, _ = crypto.GenerateKey() + + valids = make(map[uint64]struct{}) + gapped = make(map[uint64]struct{}) + ) + for _, nonce := range []uint64{0, 1, 3, 4, 6, 7} { // first gap at #2, another at #5 + tx := makeTx(nonce, 1, 1, 1, gapper) + blob, _ := rlp.EncodeToBytes(tx) + + id, _ := store.Put(blob) + if nonce < 2 { + valids[id] = struct{}{} + } else { + gapped[id] = struct{}{} + } + } + // Insert a sequence of transactions with a gapped starting nonce to verify + // that the entire set will get dropped. + var ( + dangler, _ = crypto.GenerateKey() + dangling = make(map[uint64]struct{}) + ) + for _, nonce := range []uint64{1, 2, 3} { // first gap at #0, all set dangling + tx := makeTx(nonce, 1, 1, 1, dangler) + blob, _ := rlp.EncodeToBytes(tx) + + id, _ := store.Put(blob) + dangling[id] = struct{}{} + } + // Insert a sequence of transactions with already passed nonces to veirfy + // that the entire set will get dropped. + var ( + filler, _ = crypto.GenerateKey() + filled = make(map[uint64]struct{}) + ) + for _, nonce := range []uint64{0, 1, 2} { // account nonce at 3, all set filled + tx := makeTx(nonce, 1, 1, 1, filler) + blob, _ := rlp.EncodeToBytes(tx) + + id, _ := store.Put(blob) + filled[id] = struct{}{} + } + // Insert a sequence of transactions with partially passed nonces to veirfy + // that the included part of the set will get dropped + var ( + overlapper, _ = crypto.GenerateKey() + overlapped = make(map[uint64]struct{}) + ) + for _, nonce := range []uint64{0, 1, 2, 3} { // account nonce at 2, half filled + tx := makeTx(nonce, 1, 1, 1, overlapper) + blob, _ := rlp.EncodeToBytes(tx) + + id, _ := store.Put(blob) + if nonce >= 2 { + valids[id] = struct{}{} + } else { + overlapped[id] = struct{}{} + } + } + // Insert a sequence of transactions with an underpriced first to verify that + // the entire set will get dropped (case 4). + var ( + underpayer, _ = crypto.GenerateKey() + underpaid = make(map[uint64]struct{}) + ) + for i := 0; i < 5; i++ { // make #0 underpriced + var tx *types.Transaction + if i == 0 { + tx = makeTx(uint64(i), 0, 0, 0, underpayer) + } else { + tx = makeTx(uint64(i), 1, 1, 1, underpayer) + } + blob, _ := rlp.EncodeToBytes(tx) + + id, _ := store.Put(blob) + underpaid[id] = struct{}{} + } + + // Insert a sequence of transactions with an underpriced in between to verify + // that it and anything newly gapped will get evicted (case 4). + var ( + outpricer, _ = crypto.GenerateKey() + outpriced = make(map[uint64]struct{}) + ) + for i := 0; i < 5; i++ { // make #2 underpriced + var tx *types.Transaction + if i == 2 { + tx = makeTx(uint64(i), 0, 0, 0, outpricer) + } else { + tx = makeTx(uint64(i), 1, 1, 1, outpricer) + } + blob, _ := rlp.EncodeToBytes(tx) + + id, _ := store.Put(blob) + if i < 2 { + valids[id] = struct{}{} + } else { + outpriced[id] = struct{}{} + } + } + // Insert a sequence of transactions fully overdrafted to verify that the + // entire set will get invalidated. + var ( + exceeder, _ = crypto.GenerateKey() + exceeded = make(map[uint64]struct{}) + ) + for _, nonce := range []uint64{0, 1, 2} { // nonce 0 overdrafts the account + var tx *types.Transaction + if nonce == 0 { + tx = makeTx(nonce, 1, 100, 1, exceeder) + } else { + tx = makeTx(nonce, 1, 1, 1, exceeder) + } + blob, _ := rlp.EncodeToBytes(tx) + + id, _ := store.Put(blob) + exceeded[id] = struct{}{} + } + // Insert a sequence of transactions partially overdrafted to verify that part + // of the set will get invalidated. + var ( + overdrafter, _ = crypto.GenerateKey() + overdrafted = make(map[uint64]struct{}) + ) + for _, nonce := range []uint64{0, 1, 2} { // nonce 1 overdrafts the account + var tx *types.Transaction + if nonce == 1 { + tx = makeTx(nonce, 1, 100, 1, overdrafter) + } else { + tx = makeTx(nonce, 1, 1, 1, overdrafter) + } + blob, _ := rlp.EncodeToBytes(tx) + + id, _ := store.Put(blob) + if nonce < 1 { + valids[id] = struct{}{} + } else { + overdrafted[id] = struct{}{} + } + } + // Insert a sequence of transactions overflowing the account cap to verify + // that part of the set will get invalidated. + var ( + overcapper, _ = crypto.GenerateKey() + overcapped = make(map[uint64]struct{}) + ) + for nonce := uint64(0); nonce < maxTxsPerAccount+3; nonce++ { + blob, _ := rlp.EncodeToBytes(makeTx(nonce, 1, 1, 1, overcapper)) + + id, _ := store.Put(blob) + if nonce < maxTxsPerAccount { + valids[id] = struct{}{} + } else { + overcapped[id] = struct{}{} + } + } + 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.AddBalance(crypto.PubkeyToAddress(gapper.PublicKey), big.NewInt(1000000)) + statedb.AddBalance(crypto.PubkeyToAddress(dangler.PublicKey), big.NewInt(1000000)) + statedb.AddBalance(crypto.PubkeyToAddress(filler.PublicKey), big.NewInt(1000000)) + statedb.SetNonce(crypto.PubkeyToAddress(filler.PublicKey), 3) + statedb.AddBalance(crypto.PubkeyToAddress(overlapper.PublicKey), big.NewInt(1000000)) + statedb.SetNonce(crypto.PubkeyToAddress(overlapper.PublicKey), 2) + statedb.AddBalance(crypto.PubkeyToAddress(underpayer.PublicKey), big.NewInt(1000000)) + statedb.AddBalance(crypto.PubkeyToAddress(outpricer.PublicKey), big.NewInt(1000000)) + statedb.AddBalance(crypto.PubkeyToAddress(exceeder.PublicKey), big.NewInt(1000000)) + statedb.AddBalance(crypto.PubkeyToAddress(overdrafter.PublicKey), big.NewInt(1000000)) + statedb.AddBalance(crypto.PubkeyToAddress(overcapper.PublicKey), big.NewInt(10000000)) + statedb.Commit(0, true) + + chain := &testBlockChain{ + config: testChainConfig, + basefee: uint256.NewInt(params.InitialBaseFee), + blobfee: uint256.NewInt(params.BlobTxMinBlobGasprice), + statedb: statedb, + } + pool := New(Config{Datadir: storage}, chain) + if err := pool.Init(big.NewInt(1), chain.CurrentBlock(), makeAddressReserver()); err != nil { + t.Fatalf("failed to create blob pool: %v", err) + } + defer pool.Close() + + // Verify that the malformed (case 1), badly signed (case 2) and gapped (case + // 3) txs have been deleted from the pool + alive := make(map[uint64]struct{}) + for _, txs := range pool.index { + for _, tx := range txs { + switch tx.id { + case malformed: + t.Errorf("malformed RLP transaction remained in storage") + case badsig: + t.Errorf("invalidly signed transaction remained in storage") + default: + if _, ok := dangling[tx.id]; ok { + t.Errorf("dangling transaction remained in storage: %d", tx.id) + } else if _, ok := filled[tx.id]; ok { + t.Errorf("filled transaction remained in storage: %d", tx.id) + } else if _, ok := overlapped[tx.id]; ok { + t.Errorf("overlapped transaction remained in storage: %d", tx.id) + } else if _, ok := gapped[tx.id]; ok { + t.Errorf("gapped transaction remained in storage: %d", tx.id) + } else if _, ok := underpaid[tx.id]; ok { + t.Errorf("underpaid transaction remained in storage: %d", tx.id) + } else if _, ok := outpriced[tx.id]; ok { + t.Errorf("outpriced transaction remained in storage: %d", tx.id) + } else if _, ok := exceeded[tx.id]; ok { + t.Errorf("fully overdrafted transaction remained in storage: %d", tx.id) + } else if _, ok := overdrafted[tx.id]; ok { + t.Errorf("partially overdrafted transaction remained in storage: %d", tx.id) + } else if _, ok := overcapped[tx.id]; ok { + t.Errorf("overcapped transaction remained in storage: %d", tx.id) + } else { + alive[tx.id] = struct{}{} + } + } + } + } + // Verify that the rest of the transactions remained alive + if len(alive) != len(valids) { + t.Errorf("valid transaction count mismatch: have %d, want %d", len(alive), len(valids)) + } + for id := range alive { + if _, ok := valids[id]; !ok { + t.Errorf("extra transaction %d", id) + } + } + for id := range valids { + if _, ok := alive[id]; !ok { + t.Errorf("missing transaction %d", id) + } + } + // Verify all the calculated pool internals. Interestingly, this is **not** + // a duplication of the above checks, this actually validates the verifier + // using the above already hard coded checks. + // + // Do not remove this, nor alter the above to be generic. + verifyPoolInternals(t, pool) +} + +// Tests that transactions loaded from disk are indexed corrently. +// +// - 1. Transactions must be groupped by sender, sorted by nonce +// - 2. Eviction thresholds are calculated correctly for the sequences +// - 3. Balance usage of an account is totals across all transactions +func TestOpenIndex(t *testing.T) { + log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) + + // Create a temporary folder for the persistent backend + storage, _ := os.MkdirTemp("", "blobpool-") + defer os.RemoveAll(storage) + + os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700) + store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(), nil) + + // Insert a sequence of transactions with varying price points to check that + // the cumulative minimumw will be maintained. + var ( + key, _ = crypto.GenerateKey() + addr = crypto.PubkeyToAddress(key.PublicKey) + + txExecTipCaps = []uint64{10, 25, 5, 7, 1, 100} + txExecFeeCaps = []uint64{100, 90, 200, 10, 80, 300} + txBlobFeeCaps = []uint64{55, 66, 77, 33, 22, 11} + + //basefeeJumps = []float64{39.098, 38.204, 44.983, 19.549, 37.204, 48.426} // log 1.125 (exec fee cap) + //blobfeeJumps = []float64{34.023, 35.570, 36.879, 29.686, 26.243, 20.358} // log 1.125 (blob fee cap) + + evictExecTipCaps = []uint64{10, 10, 5, 5, 1, 1} + evictExecFeeJumps = []float64{39.098, 38.204, 38.204, 19.549, 19.549, 19.549} // min(log 1.125 (exec fee cap)) + evictBlobFeeJumps = []float64{34.023, 34.023, 34.023, 29.686, 26.243, 20.358} // min(log 1.125 (blob fee cap)) + + totalSpent = uint256.NewInt(21000*(100+90+200+10+80+300) + blobSize*(55+66+77+33+22+11) + 100*6) // 21000 gas x price + 128KB x blobprice + value + ) + for _, i := range []int{5, 3, 4, 2, 0, 1} { // Randomize the tx insertion order to force sorting on load + tx := makeTx(uint64(i), txExecTipCaps[i], txExecFeeCaps[i], txBlobFeeCaps[i], key) + blob, _ := rlp.EncodeToBytes(tx) + store.Put(blob) + } + 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.AddBalance(addr, big.NewInt(1_000_000_000)) + statedb.Commit(0, true) + + chain := &testBlockChain{ + config: testChainConfig, + basefee: uint256.NewInt(params.InitialBaseFee), + blobfee: uint256.NewInt(params.BlobTxMinBlobGasprice), + statedb: statedb, + } + pool := New(Config{Datadir: storage}, chain) + if err := pool.Init(big.NewInt(1), chain.CurrentBlock(), makeAddressReserver()); err != nil { + t.Fatalf("failed to create blob pool: %v", err) + } + defer pool.Close() + + // Verify that the transactions have been sorted by nonce (case 1) + for i := 0; i < len(pool.index[addr]); i++ { + if pool.index[addr][i].nonce != uint64(i) { + t.Errorf("tx %d nonce mismatch: have %d, want %d", i, pool.index[addr][i].nonce, uint64(i)) + } + } + // Verify that the cumulative fee minimums have been correctly calculated (case 2) + for i, cap := range evictExecTipCaps { + if !pool.index[addr][i].evictionExecTip.Eq(uint256.NewInt(cap)) { + t.Errorf("eviction tip cap %d mismatch: have %d, want %d", i, pool.index[addr][i].evictionExecTip, cap) + } + } + for i, jumps := range evictExecFeeJumps { + if math.Abs(pool.index[addr][i].evictionExecFeeJumps-jumps) > 0.001 { + t.Errorf("eviction fee cap jumps %d mismatch: have %f, want %f", i, pool.index[addr][i].evictionExecFeeJumps, jumps) + } + } + for i, jumps := range evictBlobFeeJumps { + if math.Abs(pool.index[addr][i].evictionBlobFeeJumps-jumps) > 0.001 { + t.Errorf("eviction blob fee cap jumps %d mismatch: have %f, want %f", i, pool.index[addr][i].evictionBlobFeeJumps, jumps) + } + } + // Verify that the balance usage has been correctly calculated (case 3) + if !pool.spent[addr].Eq(totalSpent) { + t.Errorf("expenditure mismatch: have %d, want %d", pool.spent[addr], totalSpent) + } + // Verify all the calculated pool internals. Interestingly, this is **not** + // a duplication of the above checks, this actually validates the verifier + // using the above already hard coded checks. + // + // Do not remove this, nor alter the above to be generic. + verifyPoolInternals(t, pool) +} + +// Tests that after indexing all the loaded transactions from disk, a price heap +// is correctly constructed based on the head basefee and blobfee. +func TestOpenHeap(t *testing.T) { + log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) + + // Create a temporary folder for the persistent backend + storage, _ := os.MkdirTemp("", "blobpool-") + defer os.RemoveAll(storage) + + os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700) + store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(), nil) + + // Insert a few transactions from a few accounts. To remove randomness from + // the heap initialization, use a deterministic account/tx/priority ordering. + var ( + key1, _ = crypto.GenerateKey() + key2, _ = crypto.GenerateKey() + key3, _ = crypto.GenerateKey() + + addr1 = crypto.PubkeyToAddress(key1.PublicKey) + addr2 = crypto.PubkeyToAddress(key2.PublicKey) + addr3 = crypto.PubkeyToAddress(key3.PublicKey) + ) + if bytes.Compare(addr1[:], addr2[:]) > 0 { + key1, addr1, key2, addr2 = key2, addr2, key1, addr1 + } + if bytes.Compare(addr1[:], addr3[:]) > 0 { + key1, addr1, key3, addr3 = key3, addr3, key1, addr1 + } + if bytes.Compare(addr2[:], addr3[:]) > 0 { + key2, addr2, key3, addr3 = key3, addr3, key2, addr2 + } + var ( + tx1 = makeTx(0, 1, 1000, 90, key1) + tx2 = makeTx(0, 1, 800, 70, key2) + tx3 = makeTx(0, 1, 1500, 110, key3) + + blob1, _ = rlp.EncodeToBytes(tx1) + blob2, _ = rlp.EncodeToBytes(tx2) + blob3, _ = rlp.EncodeToBytes(tx3) + + heapOrder = []common.Address{addr2, addr1, addr3} + heapIndex = map[common.Address]int{addr2: 0, addr1: 1, addr3: 2} + ) + store.Put(blob1) + store.Put(blob2) + store.Put(blob3) + 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.AddBalance(addr1, big.NewInt(1_000_000_000)) + statedb.AddBalance(addr2, big.NewInt(1_000_000_000)) + statedb.AddBalance(addr3, big.NewInt(1_000_000_000)) + statedb.Commit(0, true) + + chain := &testBlockChain{ + config: testChainConfig, + basefee: uint256.NewInt(1050), + blobfee: uint256.NewInt(105), + statedb: statedb, + } + pool := New(Config{Datadir: storage}, chain) + if err := pool.Init(big.NewInt(1), chain.CurrentBlock(), makeAddressReserver()); err != nil { + t.Fatalf("failed to create blob pool: %v", err) + } + defer pool.Close() + + // Verify that the heap's internal state matches the expectations + for i, addr := range pool.evict.addrs { + if addr != heapOrder[i] { + t.Errorf("slot %d mismatch: have %v, want %v", i, addr, heapOrder[i]) + } + } + for addr, i := range pool.evict.index { + if i != heapIndex[addr] { + t.Errorf("index for %v mismatch: have %d, want %d", addr, i, heapIndex[addr]) + } + } + // Verify all the calculated pool internals. Interestingly, this is **not** + // a duplication of the above checks, this actually validates the verifier + // using the above already hard coded checks. + // + // Do not remove this, nor alter the above to be generic. + verifyPoolInternals(t, pool) +} + +// Tests that after the pool's previous state is loaded back, any transactions +// over the new storage cap will get dropped. +func TestOpenCap(t *testing.T) { + log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) + + // Create a temporary folder for the persistent backend + storage, _ := os.MkdirTemp("", "blobpool-") + defer os.RemoveAll(storage) + + os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700) + store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(), nil) + + // Insert a few transactions from a few accounts + var ( + key1, _ = crypto.GenerateKey() + key2, _ = crypto.GenerateKey() + key3, _ = crypto.GenerateKey() + + addr1 = crypto.PubkeyToAddress(key1.PublicKey) + addr2 = crypto.PubkeyToAddress(key2.PublicKey) + addr3 = crypto.PubkeyToAddress(key3.PublicKey) + + tx1 = makeTx(0, 1, 1000, 100, key1) + tx2 = makeTx(0, 1, 800, 70, key2) + tx3 = makeTx(0, 1, 1500, 110, key3) + + blob1, _ = rlp.EncodeToBytes(tx1) + blob2, _ = rlp.EncodeToBytes(tx2) + blob3, _ = rlp.EncodeToBytes(tx3) + + keep = []common.Address{addr1, addr3} + drop = []common.Address{addr2} + size = uint64(2 * (txAvgSize + blobSize)) + ) + store.Put(blob1) + store.Put(blob2) + store.Put(blob3) + store.Close() + + // Verify pool capping twice: first by reducing the data cap, then restarting + // 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.AddBalance(addr1, big.NewInt(1_000_000_000)) + statedb.AddBalance(addr2, big.NewInt(1_000_000_000)) + statedb.AddBalance(addr3, big.NewInt(1_000_000_000)) + statedb.Commit(0, true) + + chain := &testBlockChain{ + config: testChainConfig, + basefee: uint256.NewInt(1050), + blobfee: uint256.NewInt(105), + statedb: statedb, + } + pool := New(Config{Datadir: storage, Datacap: datacap}, chain) + if err := pool.Init(big.NewInt(1), chain.CurrentBlock(), makeAddressReserver()); err != nil { + t.Fatalf("failed to create blob pool: %v", err) + } + // Verify that enough transactions have been dropped to get the pool's size + // under the requested limit + if len(pool.index) != len(keep) { + t.Errorf("tracked account count mismatch: have %d, want %d", len(pool.index), len(keep)) + } + for _, addr := range keep { + if _, ok := pool.index[addr]; !ok { + t.Errorf("expected account %v missing from pool", addr) + } + } + for _, addr := range drop { + if _, ok := pool.index[addr]; ok { + t.Errorf("unexpected account %v present in pool", addr) + } + } + if pool.stored != size { + t.Errorf("pool stored size mismatch: have %v, want %v", pool.stored, size) + } + // Verify all the calculated pool internals. Interestingly, this is **not** + // a duplication of the above checks, this actually validates the verifier + // using the above already hard coded checks. + // + // Do not remove this, nor alter the above to be generic. + verifyPoolInternals(t, pool) + + pool.Close() + } +} + +// Tests that adding transaction will correctly store it in the persistent store +// and update all the indices. +// +// Note, this tests mostly checks the pool transaction shuffling logic or things +// specific to the blob pool. It does not do an exhaustive transaction validity +// check. +func TestAdd(t *testing.T) { + log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) + + // seed is a helper tumpe 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 + tx *types.BlobTx + err error + } + + tests := []struct { + seeds map[string]seed + adds []addtx + }{ + // Transactions from new accounts should be accepted if their initial + // nonce matches the expected one from the statedb. Higher or lower must + // be rejected. + { + seeds: map[string]seed{ + "alice": {balance: 21100 + blobSize}, + "bob": {balance: 21100 + blobSize, nonce: 1}, + "claire": {balance: 21100 + blobSize}, + "dave": {balance: 21100 + blobSize, nonce: 1}, + }, + adds: []addtx{ + { // New account, no previous txs: accept nonce 0 + from: "alice", + tx: makeUnsignedTx(0, 1, 1, 1), + err: nil, + }, + { // Old account, 1 tx in chain, 0 pending: accept nonce 1 + from: "bob", + tx: makeUnsignedTx(1, 1, 1, 1), + err: nil, + }, + { // New account, no previous txs: reject nonce 1 + from: "claire", + tx: makeUnsignedTx(1, 1, 1, 1), + err: core.ErrNonceTooHigh, + }, + { // Old account, 1 tx in chain, 0 pending: reject nonce 0 + from: "dave", + tx: makeUnsignedTx(0, 1, 1, 1), + err: core.ErrNonceTooLow, + }, + { // Old account, 1 tx in chain, 0 pending: reject nonce 2 + from: "dave", + tx: makeUnsignedTx(2, 1, 1, 1), + err: core.ErrNonceTooHigh, + }, + }, + }, + // Transactions from already pooled accounts should only be accepted if + // the nonces are contiguous (ignore prices for now, will check later) + { + seeds: map[string]seed{ + "alice": { + balance: 1000000, + txs: []*types.BlobTx{ + makeUnsignedTx(0, 1, 1, 1), + }, + }, + "bob": { + balance: 1000000, + nonce: 1, + txs: []*types.BlobTx{ + makeUnsignedTx(1, 1, 1, 1), + }, + }, + }, + adds: []addtx{ + { // New account, 1 tx pending: reject replacement nonce 0 (ignore price for now) + from: "alice", + tx: makeUnsignedTx(0, 1, 1, 1), + err: txpool.ErrReplaceUnderpriced, + }, + { // New account, 1 tx pending: accept nonce 1 + from: "alice", + tx: makeUnsignedTx(1, 1, 1, 1), + err: nil, + }, + { // New account, 2 txs pending: reject nonce 3 + from: "alice", + tx: makeUnsignedTx(3, 1, 1, 1), + err: core.ErrNonceTooHigh, + }, + { // New account, 2 txs pending: accept nonce 2 + from: "alice", + tx: makeUnsignedTx(2, 1, 1, 1), + err: nil, + }, + { // New account, 3 txs pending: accept nonce 3 now + from: "alice", + 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) + from: "bob", + tx: makeUnsignedTx(1, 1, 1, 1), + err: txpool.ErrReplaceUnderpriced, + }, + { // Old account, 1 tx in chain, 1 tx pending: accept nonce 2 (ignore price for now) + from: "bob", + tx: makeUnsignedTx(2, 1, 1, 1), + err: nil, + }, + }, + }, + // Transactions should only be accepted into the pool if the cumulative + // expenditure doesn't overflow the account balance + { + seeds: map[string]seed{ + "alice": {balance: 63299 + 3*blobSize}, // 3 tx - 1 wei + }, + adds: []addtx{ + { // New account, no previous txs: accept nonce 0 with 21100 wei spend + from: "alice", + tx: makeUnsignedTx(0, 1, 1, 1), + err: nil, + }, + { // New account, 1 pooled tx with 21100 wei spent: accept nonce 1 with 21100 wei spend + from: "alice", + tx: makeUnsignedTx(1, 1, 1, 1), + err: nil, + }, + { // New account, 2 pooled tx with 42200 wei spent: reject nonce 2 with 21100 wei spend (1 wei overflow) + from: "alice", + tx: makeUnsignedTx(2, 1, 1, 1), + err: core.ErrInsufficientFunds, + }, + }, + }, + // Transactions should only be accepted into the pool if the total count + // from the same account doesn't overflow the pool limits + { + seeds: map[string]seed{ + "alice": {balance: 10000000}, + }, + adds: []addtx{ + { // New account, no previous txs, 16 slots left: accept nonce 0 + from: "alice", + tx: makeUnsignedTx(0, 1, 1, 1), + err: nil, + }, + { // New account, 1 pooled tx, 15 slots left: accept nonce 1 + from: "alice", + tx: makeUnsignedTx(1, 1, 1, 1), + err: nil, + }, + { // New account, 2 pooled tx, 14 slots left: accept nonce 2 + from: "alice", + tx: makeUnsignedTx(2, 1, 1, 1), + err: nil, + }, + { // New account, 3 pooled tx, 13 slots left: accept nonce 3 + from: "alice", + tx: makeUnsignedTx(3, 1, 1, 1), + err: nil, + }, + { // New account, 4 pooled tx, 12 slots left: accept nonce 4 + from: "alice", + tx: makeUnsignedTx(4, 1, 1, 1), + err: nil, + }, + { // New account, 5 pooled tx, 11 slots left: accept nonce 5 + from: "alice", + tx: makeUnsignedTx(5, 1, 1, 1), + err: nil, + }, + { // New account, 6 pooled tx, 10 slots left: accept nonce 6 + from: "alice", + tx: makeUnsignedTx(6, 1, 1, 1), + err: nil, + }, + { // New account, 7 pooled tx, 9 slots left: accept nonce 7 + from: "alice", + tx: makeUnsignedTx(7, 1, 1, 1), + err: nil, + }, + { // New account, 8 pooled tx, 8 slots left: accept nonce 8 + from: "alice", + tx: makeUnsignedTx(8, 1, 1, 1), + err: nil, + }, + { // New account, 9 pooled tx, 7 slots left: accept nonce 9 + from: "alice", + tx: makeUnsignedTx(9, 1, 1, 1), + err: nil, + }, + { // New account, 10 pooled tx, 6 slots left: accept nonce 10 + from: "alice", + tx: makeUnsignedTx(10, 1, 1, 1), + err: nil, + }, + { // New account, 11 pooled tx, 5 slots left: accept nonce 11 + from: "alice", + tx: makeUnsignedTx(11, 1, 1, 1), + err: nil, + }, + { // New account, 12 pooled tx, 4 slots left: accept nonce 12 + from: "alice", + tx: makeUnsignedTx(12, 1, 1, 1), + err: nil, + }, + { // New account, 13 pooled tx, 3 slots left: accept nonce 13 + from: "alice", + tx: makeUnsignedTx(13, 1, 1, 1), + err: nil, + }, + { // New account, 14 pooled tx, 2 slots left: accept nonce 14 + from: "alice", + tx: makeUnsignedTx(14, 1, 1, 1), + err: nil, + }, + { // New account, 15 pooled tx, 1 slots left: accept nonce 15 + from: "alice", + tx: makeUnsignedTx(15, 1, 1, 1), + err: nil, + }, + { // New account, 16 pooled tx, 0 slots left: accept nonce 15 replacement + from: "alice", + tx: makeUnsignedTx(15, 10, 10, 10), + err: nil, + }, + { // New account, 16 pooled tx, 0 slots left: reject nonce 16 with overcap + from: "alice", + tx: makeUnsignedTx(16, 1, 1, 1), + err: txpool.ErrAccountLimitExceeded, + }, + }, + }, + // Previously existing transactions should be allowed to be replaced iff + // the new cumulative expenditure can be covered by the account and the + // prices are bumped all around (no percentage check here). + { + seeds: map[string]seed{ + "alice": {balance: 2*100 + 5*21000 + 3*blobSize}, + }, + adds: []addtx{ + { // New account, no previous txs: reject nonce 0 with 341172 wei spend + from: "alice", + tx: makeUnsignedTx(0, 1, 20, 1), + err: core.ErrInsufficientFunds, + }, + { // New account, no previous txs: accept nonce 0 with 173172 wei spend + from: "alice", + tx: makeUnsignedTx(0, 1, 2, 1), + err: nil, + }, + { // New account, 1 pooled tx with 173172 wei spent: accept nonce 1 with 152172 wei spend + from: "alice", + tx: makeUnsignedTx(1, 1, 1, 1), + err: nil, + }, + { // New account, 2 pooled tx with 325344 wei spent: reject nonce 0 with 599684 wei spend (173072 extra) (would overflow balance at nonce 1) + from: "alice", + tx: makeUnsignedTx(0, 2, 5, 2), + err: core.ErrInsufficientFunds, + }, + { // New account, 2 pooled tx with 325344 wei spent: reject nonce 0 with no-gastip-bump + from: "alice", + tx: makeUnsignedTx(0, 1, 3, 2), + err: txpool.ErrReplaceUnderpriced, + }, + { // New account, 2 pooled tx with 325344 wei spent: reject nonce 0 with no-gascap-bump + from: "alice", + tx: makeUnsignedTx(0, 2, 2, 2), + err: txpool.ErrReplaceUnderpriced, + }, + { // New account, 2 pooled tx with 325344 wei spent: reject nonce 0 with no-blobcap-bump + from: "alice", + tx: makeUnsignedTx(0, 2, 4, 1), + err: txpool.ErrReplaceUnderpriced, + }, + { // New account, 2 pooled tx with 325344 wei spent: accept nonce 0 with 84100 wei spend (42000 extra) + from: "alice", + tx: makeUnsignedTx(0, 2, 4, 2), + err: nil, + }, + }, + }, + // Previously existing transactions should be allowed to be replaced iff + // the new prices are bumped by a sufficient amount. + { + seeds: map[string]seed{ + "alice": {balance: 100 + 8*21000 + 4*blobSize}, + }, + adds: []addtx{ + { // New account, no previous txs: accept nonce 0 + from: "alice", + tx: makeUnsignedTx(0, 2, 4, 2), + err: nil, + }, + { // New account, 1 pooled tx: reject nonce 0 with low-gastip-bump + from: "alice", + tx: makeUnsignedTx(0, 3, 8, 4), + err: txpool.ErrReplaceUnderpriced, + }, + { // New account, 1 pooled tx: reject nonce 0 with low-gascap-bump + from: "alice", + tx: makeUnsignedTx(0, 4, 6, 4), + err: txpool.ErrReplaceUnderpriced, + }, + { // New account, 1 pooled tx: reject nonce 0 with low-blobcap-bump + from: "alice", + tx: makeUnsignedTx(0, 4, 8, 3), + err: txpool.ErrReplaceUnderpriced, + }, + { // New account, 1 pooled tx: accept nonce 0 with all-bumps + from: "alice", + tx: makeUnsignedTx(0, 4, 8, 4), + err: nil, + }, + }, + }, + } + for i, tt := range tests { + // Create a temporary folder for the persistent backend + storage, _ := os.MkdirTemp("", "blobpool-") + defer os.RemoveAll(storage) // late defer, still ok + + os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700) + store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(), nil) + + // Insert the seed transactions for the pool startup + var ( + keys = make(map[string]*ecdsa.PrivateKey) + addrs = make(map[string]common.Address) + ) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil) + for acc, seed := range tt.seeds { + // Generate a new random key/address for the seed account + keys[acc], _ = crypto.GenerateKey() + addrs[acc] = crypto.PubkeyToAddress(keys[acc].PublicKey) + + // Seed the state database with this acocunt + statedb.AddBalance(addrs[acc], new(big.Int).SetUint64(seed.balance)) + statedb.SetNonce(addrs[acc], seed.nonce) + + // 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) + blob, _ := rlp.EncodeToBytes(signed) + store.Put(blob) + } + } + statedb.Commit(0, true) + store.Close() + + // Create a blob pool out of the pre-seeded dats + chain := &testBlockChain{ + config: testChainConfig, + basefee: uint256.NewInt(1050), + blobfee: uint256.NewInt(105), + statedb: statedb, + } + pool := New(Config{Datadir: storage}, chain) + if err := pool.Init(big.NewInt(1), chain.CurrentBlock(), makeAddressReserver()); err != nil { + t.Fatalf("test %d: failed to create blob pool: %v", i, err) + } + verifyPoolInternals(t, pool) + + // 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) + 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) + pool.Close() + } +} diff --git a/core/txpool/blobpool/config.go b/core/txpool/blobpool/config.go new file mode 100644 index 0000000000..99a2002a30 --- /dev/null +++ b/core/txpool/blobpool/config.go @@ -0,0 +1,50 @@ +// 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 blobpool + +import ( + "github.com/ethereum/go-ethereum/log" +) + +// Config are the configuration parameters of the blob transaction pool. +type Config struct { + Datadir string // Data directory containing the currently executable blobs + Datacap uint64 // Soft-cap of database storage (hard cap is larger due to overhead) + PriceBump uint64 // Minimum price bump percentage to replace an already existing nonce +} + +// DefaultConfig contains the default configurations for the transaction pool. +var DefaultConfig = Config{ + Datadir: "blobpool", + Datacap: 10 * 1024 * 1024 * 1024, + PriceBump: 100, // either have patience or be aggressive, no mushy ground +} + +// sanitize checks the provided user configurations and changes anything that's +// unreasonable or unworkable. +func (config *Config) sanitize() Config { + conf := *config + if conf.Datacap < 1 { + log.Warn("Sanitizing invalid blobpool storage cap", "provided", conf.Datacap, "updated", DefaultConfig.Datacap) + conf.Datacap = DefaultConfig.Datacap + } + if conf.PriceBump < 1 { + log.Warn("Sanitizing invalid blobpool price bump", "provided", conf.PriceBump, "updated", DefaultConfig.PriceBump) + conf.PriceBump = DefaultConfig.PriceBump + } + return conf +} diff --git a/core/txpool/blobpool/evictheap.go b/core/txpool/blobpool/evictheap.go new file mode 100644 index 0000000000..7607a911c1 --- /dev/null +++ b/core/txpool/blobpool/evictheap.go @@ -0,0 +1,146 @@ +// 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 blobpool + +import ( + "bytes" + "container/heap" + "math" + "sort" + + "github.com/ethereum/go-ethereum/common" + "github.com/holiman/uint256" +) + +// evictHeap is a helper data structure to keep track of the cheapest bottleneck +// transaction from each account to determine which account to evict from. +// +// The heap internally tracks a slice of cheapest transactions from each account +// and a mapping from addresses to indices for direct removals/udates. +// +// 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 + + basefeeJumps float64 // Pre-calculated absolute dynamic fee jumps for the base fee + blobfeeJumps float64 // Pre-calculated absolute dynamic fee jumps for the blob fee + + addrs []common.Address // Heap of addresses to retrieve the cheapest out of + index map[common.Address]int // Indices into the heap for replacements +} + +// newPriceHeap creates a new heap of cheapets 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 { + heap := &evictHeap{ + metas: index, + index: make(map[common.Address]int), + } + // 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.reinit(basefee, blobfee, true) + return heap +} + +// reinit updates the pre-calculated dynamic fee jumps in the price heap and runs +// the sorting algorithm from scratch on the entire heap. +func (h *evictHeap) reinit(basefee *uint256.Int, blobfee *uint256.Int, force bool) { + // If the update is mostly the same as the old, don't sort pointlessly + basefeeJumps := dynamicFeeJumps(basefee) + blobfeeJumps := dynamicFeeJumps(blobfee) + + if !force && math.Abs(h.basefeeJumps-basefeeJumps) < 0.01 && math.Abs(h.blobfeeJumps-blobfeeJumps) < 0.01 { // TODO(karalabe): 0.01 enough, maybe should be smaller? Maybe this optimization is moot? + return + } + // One or both of the dynamic fees jumped, resort the pool + h.basefeeJumps = basefeeJumps + h.blobfeeJumps = blobfeeJumps + + heap.Init(h) +} + +// Len implements sort.Interface as part of heap.Interface, returning the number +// of accounts in the pool which can be considered for eviction. +func (h *evictHeap) Len() int { + return len(h.addrs) +} + +// 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]] + + lastI := txsI[len(txsI)-1] + lastJ := txsJ[len(txsJ)-1] + + prioI := evictionPriority(h.basefeeJumps, lastI.evictionExecFeeJumps, h.blobfeeJumps, lastI.evictionBlobFeeJumps) + if prioI > 0 { + prioI = 0 + } + prioJ := evictionPriority(h.basefeeJumps, lastJ.evictionExecFeeJumps, h.blobfeeJumps, lastJ.evictionBlobFeeJumps) + if prioJ > 0 { + prioJ = 0 + } + if prioI == prioJ { + return lastI.evictionExecTip.Lt(lastJ.evictionExecTip) + } + return prioI < prioJ +} + +// Swap implements sort.Interface as part of heap.Interface, maintaining both the +// order of the accounts according to the heap, and the account->item slot mapping +// for replacements. +func (h *evictHeap) Swap(i, j int) { + h.index[h.addrs[i]], h.index[h.addrs[j]] = h.index[h.addrs[j]], h.index[h.addrs[i]] + h.addrs[i], h.addrs[j] = h.addrs[j], h.addrs[i] +} + +// Push implements heap.Interface, appending an item to the end of the account +// ordering as well as the address to item slot mapping. +func (h *evictHeap) Push(x any) { + h.index[x.(common.Address)] = len(h.addrs) + h.addrs = append(h.addrs, x.(common.Address)) +} + +// Pop implements heap.Interface, removing and returning the last element of the +// heap. +// +// Note, use `heap.Pop`, not `evictHeap.Pop`. This method is used by Go's heap, +// to provide the functionality, it does not embed it. +func (h *evictHeap) Pop() any { + // Remove the last element from the heap + size := len(h.addrs) + addr := h.addrs[size-1] + h.addrs = h.addrs[:size-1] + + // Unindex the removed element and return + delete(h.index, addr) + return addr +} diff --git a/core/txpool/blobpool/evictheap_test.go b/core/txpool/blobpool/evictheap_test.go new file mode 100644 index 0000000000..01b136551c --- /dev/null +++ b/core/txpool/blobpool/evictheap_test.go @@ -0,0 +1,320 @@ +// 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 blobpool + +import ( + "container/heap" + mrand "math/rand" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/params" + "github.com/holiman/uint256" +) + +var rand = mrand.New(mrand.NewSource(1)) + +// verifyHeapInternals verifies that all accounts present in the index are also +// present in the heap and internals are consistent across various indices. +func verifyHeapInternals(t *testing.T, evict *evictHeap) { + t.Helper() + + // Ensure that all accounts are present in the heap and no extras + seen := make(map[common.Address]struct{}) + for i, addr := range evict.addrs { + seen[addr] = struct{}{} + if _, ok := (*evict.metas)[addr]; !ok { + t.Errorf("heap contains unexpected address at slot %d: %v", i, addr) + } + } + 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)) + } + // Ensure that all accounts are present in the heap order index and no extras + have := make([]common.Address, len(evict.index)) + for addr, i := range evict.index { + have[i] = addr + } + if len(have) != len(evict.addrs) { + t.Errorf("heap index size %d mismatches heap size %d", len(have), len(evict.addrs)) + } + for i := 0; i < len(have) && i < len(evict.addrs); i++ { + if have[i] != evict.addrs[i] { + t.Errorf("heap index for slot %d mismatches: have %v, want %v", i, have[i], evict.addrs[i]) + } + } +} + +// Tests that the price heap can correctly sort its set of transactions based on +// an input base- and blob fee. +func TestPriceHeapSorting(t *testing.T) { + tests := []struct { + execTips []uint64 + execFees []uint64 + blobFees []uint64 + + basefee uint64 + blobfee uint64 + + order []int + }{ + // If everything is above the basefee and blobfee, order by miner tip + { + execTips: []uint64{1, 0, 2}, + execFees: []uint64{1, 2, 3}, + blobFees: []uint64{3, 2, 1}, + basefee: 0, + blobfee: 0, + order: []int{1, 0, 2}, + }, + // If only basefees are used (blob fee matches with network), return the + // ones the furthest below the current basefee, splitting same ones with + // the tip. Anything above the basefee should be split by tip. + { + execTips: []uint64{100, 50, 100, 50, 1, 2, 3}, + execFees: []uint64{1000, 1000, 500, 500, 2000, 2000, 2000}, + blobFees: []uint64{0, 0, 0, 0, 0, 0, 0}, + basefee: 1999, + blobfee: 0, + order: []int{3, 2, 1, 0, 4, 5, 6}, + }, + // If only blobfees are used (base fee matches with network), return the + // ones the furthest below the current blobfee, splitting same ones with + // the tip. Anything above the blobfee should be split by tip. + { + execTips: []uint64{100, 50, 100, 50, 1, 2, 3}, + execFees: []uint64{0, 0, 0, 0, 0, 0, 0}, + blobFees: []uint64{1000, 1000, 500, 500, 2000, 2000, 2000}, + basefee: 0, + blobfee: 1999, + order: []int{3, 2, 1, 0, 4, 5, 6}, + }, + // If both basefee and blobfee is specified, sort by the larger distance + // of the two from the current network conditions, splitting same (loglog) + // ones via the tip. + // + // Basefee: 1000 + // Blobfee: 100 + // + // Tx #0: (800, 80) - 2 jumps below both => priority -1 + // Tx #1: (630, 63) - 4 jumps below both => priority -2 + // Tx #2: (800, 63) - 2 jumps below basefee, 4 jumps below blobfee => priority -2 (blob penalty dominates) + // Tx #3: (630, 80) - 4 jumps below basefee, 2 jumps below blobfee => priority -2 (base penalty dominates) + // + // Txs 1, 2, 3 share the same priority, split via tip, prefer 0 as the best + { + execTips: []uint64{1, 2, 3, 4}, + execFees: []uint64{800, 630, 800, 630}, + blobFees: []uint64{80, 63, 63, 80}, + basefee: 1000, + blobfee: 100, + order: []int{1, 2, 3, 0}, + }, + } + for i, tt := range tests { + // Create an index of the transactions + index := make(map[common.Address][]*blobTxMeta) + for j := byte(0); j < byte(len(tt.execTips)); j++ { + addr := common.Address{j} + + var ( + execTip = uint256.NewInt(tt.execTips[j]) + execFee = uint256.NewInt(tt.execFees[j]) + blobFee = uint256.NewInt(tt.blobFees[j]) + + basefeeJumps = dynamicFeeJumps(execFee) + blobfeeJumps = dynamicFeeJumps(blobFee) + ) + index[addr] = []*blobTxMeta{{ + id: uint64(j), + size: 128 * 1024, + nonce: 0, + execTipCap: execTip, + execFeeCap: execFee, + blobFeeCap: blobFee, + basefeeJumps: basefeeJumps, + blobfeeJumps: blobfeeJumps, + evictionExecTip: execTip, + evictionExecFeeJumps: basefeeJumps, + evictionBlobFeeJumps: blobfeeJumps, + }} + } + // Create a price heap and check the pop order + priceheap := newPriceHeap(uint256.NewInt(tt.basefee), uint256.NewInt(tt.blobfee), &index) + verifyHeapInternals(t, priceheap) + + for j := 0; j < len(tt.order); j++ { + if next := heap.Pop(priceheap); int(next.(common.Address)[0]) != tt.order[j] { + t.Errorf("test %d, item %d: order mismatch: have %d, want %d", i, j, next.(common.Address)[0], tt.order[j]) + } else { + delete(index, next.(common.Address)) // remove to simulate a correct pool for the test + } + verifyHeapInternals(t, priceheap) + } + } +} + +// Benchmarks reheaping the entire set of accounts in the blob pool. +func BenchmarkPriceHeapReinit1MB(b *testing.B) { benchmarkPriceHeapReinit(b, 1024*1024) } +func BenchmarkPriceHeapReinit10MB(b *testing.B) { benchmarkPriceHeapReinit(b, 10*1024*1024) } +func BenchmarkPriceHeapReinit100MB(b *testing.B) { benchmarkPriceHeapReinit(b, 100*1024*1024) } +func BenchmarkPriceHeapReinit1GB(b *testing.B) { benchmarkPriceHeapReinit(b, 1024*1024*1024) } +func BenchmarkPriceHeapReinit10GB(b *testing.B) { benchmarkPriceHeapReinit(b, 10*1024*1024*1024) } +func BenchmarkPriceHeapReinit25GB(b *testing.B) { benchmarkPriceHeapReinit(b, 25*1024*1024*1024) } +func BenchmarkPriceHeapReinit50GB(b *testing.B) { benchmarkPriceHeapReinit(b, 50*1024*1024*1024) } +func BenchmarkPriceHeapReinit100GB(b *testing.B) { benchmarkPriceHeapReinit(b, 100*1024*1024*1024) } + +func benchmarkPriceHeapReinit(b *testing.B, datacap uint64) { + // Calculate how many unique transactions we can fit into the provided disk + // data cap + blobs := datacap / (params.BlobTxBytesPerFieldElement * params.BlobTxFieldElementsPerBlob) + + // Create a random set of transactions with random fees. Use a separate account + // for each transaction to make it worse case. + index := make(map[common.Address][]*blobTxMeta) + for i := 0; i < int(blobs); i++ { + var addr common.Address + rand.Read(addr[:]) + + var ( + execTip = uint256.NewInt(rand.Uint64()) + execFee = uint256.NewInt(rand.Uint64()) + blobFee = uint256.NewInt(rand.Uint64()) + + basefeeJumps = dynamicFeeJumps(execFee) + blobfeeJumps = dynamicFeeJumps(blobFee) + ) + index[addr] = []*blobTxMeta{{ + id: uint64(i), + size: 128 * 1024, + nonce: 0, + execTipCap: execTip, + execFeeCap: execFee, + blobFeeCap: blobFee, + basefeeJumps: basefeeJumps, + blobfeeJumps: blobfeeJumps, + evictionExecTip: execTip, + evictionExecFeeJumps: basefeeJumps, + evictionBlobFeeJumps: blobfeeJumps, + }} + } + // Create a price heap and reinit it over and over + heap := newPriceHeap(uint256.NewInt(rand.Uint64()), uint256.NewInt(rand.Uint64()), &index) + + basefees := make([]*uint256.Int, b.N) + blobfees := make([]*uint256.Int, b.N) + for i := 0; i < b.N; i++ { + basefees[i] = uint256.NewInt(rand.Uint64()) + blobfees[i] = uint256.NewInt(rand.Uint64()) + } + b.ResetTimer() + b.ReportAllocs() + for i := 0; i < b.N; i++ { + heap.reinit(basefees[i], blobfees[i], true) + } +} + +// Benchmarks overflowing the heap over and over (add and then drop). +func BenchmarkPriceHeapOverflow1MB(b *testing.B) { benchmarkPriceHeapOverflow(b, 1024*1024) } +func BenchmarkPriceHeapOverflow10MB(b *testing.B) { benchmarkPriceHeapOverflow(b, 10*1024*1024) } +func BenchmarkPriceHeapOverflow100MB(b *testing.B) { benchmarkPriceHeapOverflow(b, 100*1024*1024) } +func BenchmarkPriceHeapOverflow1GB(b *testing.B) { benchmarkPriceHeapOverflow(b, 1024*1024*1024) } +func BenchmarkPriceHeapOverflow10GB(b *testing.B) { benchmarkPriceHeapOverflow(b, 10*1024*1024*1024) } +func BenchmarkPriceHeapOverflow25GB(b *testing.B) { benchmarkPriceHeapOverflow(b, 25*1024*1024*1024) } +func BenchmarkPriceHeapOverflow50GB(b *testing.B) { benchmarkPriceHeapOverflow(b, 50*1024*1024*1024) } +func BenchmarkPriceHeapOverflow100GB(b *testing.B) { benchmarkPriceHeapOverflow(b, 100*1024*1024*1024) } + +func benchmarkPriceHeapOverflow(b *testing.B, datacap uint64) { + // Calculate how many unique transactions we can fit into the provided disk + // data cap + blobs := datacap / (params.BlobTxBytesPerFieldElement * params.BlobTxFieldElementsPerBlob) + + // Create a random set of transactions with random fees. Use a separate account + // for each transaction to make it worse case. + index := make(map[common.Address][]*blobTxMeta) + for i := 0; i < int(blobs); i++ { + var addr common.Address + rand.Read(addr[:]) + + var ( + execTip = uint256.NewInt(rand.Uint64()) + execFee = uint256.NewInt(rand.Uint64()) + blobFee = uint256.NewInt(rand.Uint64()) + + basefeeJumps = dynamicFeeJumps(execFee) + blobfeeJumps = dynamicFeeJumps(blobFee) + ) + index[addr] = []*blobTxMeta{{ + id: uint64(i), + size: 128 * 1024, + nonce: 0, + execTipCap: execTip, + execFeeCap: execFee, + blobFeeCap: blobFee, + basefeeJumps: basefeeJumps, + blobfeeJumps: blobfeeJumps, + evictionExecTip: execTip, + evictionExecFeeJumps: basefeeJumps, + evictionBlobFeeJumps: blobfeeJumps, + }} + } + // Create a price heap and overflow it over and over + evict := newPriceHeap(uint256.NewInt(rand.Uint64()), uint256.NewInt(rand.Uint64()), &index) + var ( + addrs = make([]common.Address, b.N) + metas = make([]*blobTxMeta, b.N) + ) + for i := 0; i < b.N; i++ { + rand.Read(addrs[i][:]) + + var ( + execTip = uint256.NewInt(rand.Uint64()) + execFee = uint256.NewInt(rand.Uint64()) + blobFee = uint256.NewInt(rand.Uint64()) + + basefeeJumps = dynamicFeeJumps(execFee) + blobfeeJumps = dynamicFeeJumps(blobFee) + ) + metas[i] = &blobTxMeta{ + id: uint64(int(blobs) + i), + size: 128 * 1024, + nonce: 0, + execTipCap: execTip, + execFeeCap: execFee, + blobFeeCap: blobFee, + basefeeJumps: basefeeJumps, + blobfeeJumps: blobfeeJumps, + evictionExecTip: execTip, + evictionExecFeeJumps: basefeeJumps, + evictionBlobFeeJumps: blobfeeJumps, + } + } + b.ResetTimer() + b.ReportAllocs() + for i := 0; i < b.N; i++ { + index[addrs[i]] = []*blobTxMeta{metas[i]} + heap.Push(evict, addrs[i]) + + drop := heap.Pop(evict) + delete(index, drop.(common.Address)) + } +} diff --git a/core/txpool/blobpool/interface.go b/core/txpool/blobpool/interface.go new file mode 100644 index 0000000000..6f296a54bd --- /dev/null +++ b/core/txpool/blobpool/interface.go @@ -0,0 +1,44 @@ +// 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 blobpool + +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/params" +) + +// BlockChain defines the minimal set of methods needed to back a blob pool with +// a chain. Exists to allow mocking the live chain out of tests. +type BlockChain interface { + // Config retrieves the chain's fork configuration. + Config() *params.ChainConfig + + // CurrentBlock returns the current head of the chain. + CurrentBlock() *types.Header + + // CurrentFinalBlock returns the current block below which blobs should not + // be maintained anymore for reorg purposes. + CurrentFinalBlock() *types.Header + + // GetBlock retrieves a specific block, used during pool resets. + GetBlock(hash common.Hash, number uint64) *types.Block + + // StateAt returns a state database for a given root hash (generally the head). + StateAt(root common.Hash) (*state.StateDB, error) +} diff --git a/core/txpool/blobpool/limbo.go b/core/txpool/blobpool/limbo.go new file mode 100644 index 0000000000..2d62593de6 --- /dev/null +++ b/core/txpool/blobpool/limbo.go @@ -0,0 +1,253 @@ +// 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 blobpool + +import ( + "errors" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/rlp" + "github.com/holiman/billy" +) + +// limboBlob is a wrapper around an opaque blobset that also contains the tx hash +// to which it belongs as well as the block number in which it was included for +// finality eviction. +type limboBlob struct { + TxHash common.Hash // Owner transaction's hash to support resurrecting reorged txs + Block uint64 // Block in which the blob transaction was included + Tx *types.Transaction +} + +// limbo is a light, indexed database to temporarily store recently included +// blobs until they are finalized. The purpose is to support small reorgs, which +// would require pulling back up old blobs (which aren't part of the chain). +// +// TODO(karalabe): Currently updating the inclusion block of a blob needs a full db rewrite. Can we do without? +type limbo struct { + store billy.Database // Persistent data store for limboed blobs + + index map[common.Hash]uint64 // Mappings from tx hashes to datastore ids + groups map[uint64]map[uint64]common.Hash // Set of txs included in past blocks +} + +// newLimbo opens and indexes a set of limboed blob transactions. +func newLimbo(datadir string) (*limbo, error) { + l := &limbo{ + index: make(map[common.Hash]uint64), + groups: make(map[uint64]map[uint64]common.Hash), + } + // Index all limboed blobs on disk and delete anything inprocessable + var fails []uint64 + index := func(id uint64, size uint32, data []byte) { + if l.parseBlob(id, data) != nil { + fails = append(fails, id) + } + } + store, err := billy.Open(billy.Options{Path: datadir}, newSlotter(), index) + if err != nil { + return nil, err + } + l.store = store + + if len(fails) > 0 { + log.Warn("Dropping invalidated limboed blobs", "ids", fails) + for _, id := range fails { + if err := l.store.Delete(id); err != nil { + l.Close() + return nil, err + } + } + } + return l, nil +} + +// Close closes down the underlying persistent store. +func (l *limbo) Close() error { + return l.store.Close() +} + +// parseBlob is a callback method on limbo creation that gets called for each +// limboed blob on disk to create the in-memory metadata index. +func (l *limbo) parseBlob(id uint64, data []byte) error { + item := new(limboBlob) + if err := rlp.DecodeBytes(data, item); err != nil { + // This path is impossible unless the disk data representation changes + // across restarts. For that ever unprobable case, recover gracefully + // by ignoring this data entry. + log.Error("Failed to decode blob limbo entry", "id", id, "err", err) + return err + } + if _, ok := l.index[item.TxHash]; ok { + // This path is impossible, unless due to a programming error a blob gets + // inserted into the limbo which was already part of if. Recover gracefully + // by ignoring this data entry. + log.Error("Dropping duplicate blob limbo entry", "owner", item.TxHash, "id", id) + return errors.New("duplicate blob") + } + l.index[item.TxHash] = id + + if _, ok := l.groups[item.Block]; !ok { + l.groups[item.Block] = make(map[uint64]common.Hash) + } + l.groups[item.Block][id] = item.TxHash + + return nil +} + +// finalize evicts all blobs belonging to a recently finalized block or older. +func (l *limbo) finalize(final *types.Header) { + // Just in case there's no final block yet (network not yet merged, weird + // restart, sethead, etc), fail gracefully. + if final == nil { + log.Error("Nil finalized block cannot evict old blobs") + return + } + for block, ids := range l.groups { + if block > final.Number.Uint64() { + continue + } + for id, owner := range ids { + if err := l.store.Delete(id); err != nil { + log.Error("Failed to drop finalized blob", "block", block, "id", id, "err", err) + } + delete(l.index, owner) + } + delete(l.groups, block) + } +} + +// push stores a new blob transaction into the limbo, waiting until finality for +// it to be automatically evicted. +func (l *limbo) push(tx *types.Transaction, block uint64) error { + // If the blobs are already tracked by the limbo, consider it a programming + // error. There's not much to do against it, but be loud. + if _, ok := l.index[tx.Hash()]; ok { + log.Error("Limbo cannot push already tracked blobs", "tx", tx) + return errors.New("already tracked blob transaction") + } + if err := l.setAndIndex(tx, block); err != nil { + log.Error("Failed to set and index liboed blobs", "tx", tx, "err", err) + return err + } + return nil +} + +// pull retrieves a previously pushed set of blobs back from the limbo, removing +// it at the same time. This method should be used when a previously included blob +// transaction gets reorged out. +func (l *limbo) pull(tx common.Hash) (*types.Transaction, error) { + // If the blobs are not tracked by the limbo, there's not much to do. This + // can happen for example if a blob transaction is mined without pushing it + // into the network first. + id, ok := l.index[tx] + if !ok { + log.Trace("Limbo cannot pull non-tracked blobs", "tx", tx) + return nil, errors.New("unseen blob transaction") + } + item, err := l.getAndDrop(id) + if err != nil { + log.Error("Failed to get and drop limboed blobs", "tx", tx, "id", id, "err", err) + return nil, err + } + return item.Tx, nil +} + +// update changes the block number under which a blob transaction is tracked. This +// method should be used when a reorg changes a transaction's inclusion block. +// +// The method may log errors for various unexpcted scenarios but will not return +// any of it since there's no clear error case. Some errors may be due to coding +// issues, others caused by signers mining MEV stuff or swapping transactions. In +// all cases, the pool needs to continue operating. +func (l *limbo) update(txhash common.Hash, block uint64) { + // If the blobs are not tracked by the limbo, there's not much to do. This + // can happen for example if a blob transaction is mined without pushing it + // into the network first. + id, ok := l.index[txhash] + if !ok { + log.Trace("Limbo cannot update non-tracked blobs", "tx", txhash) + return + } + // If there was no change in the blob's inclusion block, don't mess around + // with heavy database operations. + if _, ok := l.groups[block][id]; ok { + log.Trace("Blob transaction unchanged in limbo", "tx", txhash, "block", block) + return + } + // Retrieve the old blobs from the data store and write tehm back with a new + // block number. IF anything fails, there's not much to do, go on. + item, err := l.getAndDrop(id) + if err != nil { + log.Error("Failed to get and drop limboed blobs", "tx", txhash, "id", id, "err", err) + return + } + if err := l.setAndIndex(item.Tx, block); err != nil { + log.Error("Failed to set and index limboed blobs", "tx", txhash, "err", err) + return + } + log.Trace("Blob transaction updated in limbo", "tx", txhash, "old-block", item.Block, "new-block", block) +} + +// getAndDrop retrieves a blob item from the limbo store and deletes it both from +// the store and indices. +func (l *limbo) getAndDrop(id uint64) (*limboBlob, error) { + data, err := l.store.Get(id) + if err != nil { + return nil, err + } + item := new(limboBlob) + if err = rlp.DecodeBytes(data, item); err != nil { + return nil, err + } + delete(l.index, item.TxHash) + delete(l.groups[item.Block], id) + if len(l.groups[item.Block]) == 0 { + delete(l.groups, item.Block) + } + if err := l.store.Delete(id); err != nil { + return nil, err + } + return item, nil +} + +// setAndIndex assembles a limbo blob database entry and stores it, also updating +// the in-memory indices. +func (l *limbo) setAndIndex(tx *types.Transaction, block uint64) error { + txhash := tx.Hash() + item := &limboBlob{ + TxHash: txhash, + Block: block, + Tx: tx, + } + data, err := rlp.EncodeToBytes(item) + if err != nil { + panic(err) // cannot happen runtime, dev error + } + id, err := l.store.Put(data) + if err != nil { + return err + } + l.index[txhash] = id + if _, ok := l.groups[block]; !ok { + l.groups[block] = make(map[uint64]common.Hash) + } + l.groups[block][id] = txhash + return nil +} diff --git a/core/txpool/blobpool/metrics.go b/core/txpool/blobpool/metrics.go new file mode 100644 index 0000000000..070cc5ca47 --- /dev/null +++ b/core/txpool/blobpool/metrics.go @@ -0,0 +1,78 @@ +// 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 blobpool + +import "github.com/ethereum/go-ethereum/metrics" + +var ( + // datacapGauge tracks the user's configured capacity for the blob pool. It + // is mostly a way to expose/debug issues. + datacapGauge = metrics.NewRegisteredGauge("blobpool/datacap", nil) + + // The below metrics track the per-datastore metrics for the primary blob + // store and the temporary limbo store. + datausedGauge = metrics.NewRegisteredGauge("blobpool/dataused", nil) + datarealGauge = metrics.NewRegisteredGauge("blobpool/datareal", nil) + slotusedGauge = metrics.NewRegisteredGauge("blobpool/slotused", nil) + + limboDatausedGauge = metrics.NewRegisteredGauge("blobpool/limbo/dataused", nil) + limboDatarealGauge = metrics.NewRegisteredGauge("blobpool/limbo/datareal", nil) + limboSlotusedGauge = metrics.NewRegisteredGauge("blobpool/limbo/slotused", nil) + + // The below metrics track the per-shelf metrics for the primary blob store + // and the temporary limbo store. + shelfDatausedGaugeName = "blobpool/shelf_%d/dataused" + shelfDatagapsGaugeName = "blobpool/shelf_%d/datagaps" + shelfSlotusedGaugeName = "blobpool/shelf_%d/slotused" + shelfSlotgapsGaugeName = "blobpool/shelf_%d/slotgaps" + + limboShelfDatausedGaugeName = "blobpool/limbo/shelf_%d/dataused" + limboShelfDatagapsGaugeName = "blobpool/limbo/shelf_%d/datagaps" + limboShelfSlotusedGaugeName = "blobpool/limbo/shelf_%d/slotused" + limboShelfSlotgapsGaugeName = "blobpool/limbo/shelf_%d/slotgaps" + + // The oversized metrics aggregate the shelf stats above the max blob count + // limits to track transactions that are just huge, but don't contain blobs. + // + // There are no oversized data in the limbo, it only contains blobs and some + // constant metadata. + oversizedDatausedGauge = metrics.NewRegisteredGauge("blobpool/oversized/dataused", nil) + oversizedDatagapsGauge = metrics.NewRegisteredGauge("blobpool/oversized/datagaps", nil) + oversizedSlotusedGauge = metrics.NewRegisteredGauge("blobpool/oversized/slotused", nil) + oversizedSlotgapsGauge = metrics.NewRegisteredGauge("blobpool/oversized/slotgaps", nil) + + // basefeeGauge and blobfeeGauge track the current network 1559 base fee and + // 4844 blob fee respectively. + basefeeGauge = metrics.NewRegisteredGauge("blobpool/basefee", nil) + blobfeeGauge = metrics.NewRegisteredGauge("blobpool/blobfee", nil) + + // pooltipGauge is the configurable miner tip to permit a transaction into + // the pool. + pooltipGauge = metrics.NewRegisteredGauge("blobpool/pooltip", nil) + + // addwait/time, resetwait/time and getwait/time track the rough health of + // the pool and wether or not it's capable of keeping up with the load from + // the network. + addwaitHist = metrics.NewRegisteredHistogram("blobpool/addwait", nil, metrics.NewExpDecaySample(1028, 0.015)) + addtimeHist = metrics.NewRegisteredHistogram("blobpool/addtime", nil, metrics.NewExpDecaySample(1028, 0.015)) + getwaitHist = metrics.NewRegisteredHistogram("blobpool/getwait", nil, metrics.NewExpDecaySample(1028, 0.015)) + gettimeHist = metrics.NewRegisteredHistogram("blobpool/gettime", nil, metrics.NewExpDecaySample(1028, 0.015)) + pendwaitHist = metrics.NewRegisteredHistogram("blobpool/pendwait", nil, metrics.NewExpDecaySample(1028, 0.015)) + pendtimeHist = metrics.NewRegisteredHistogram("blobpool/pendtime", nil, metrics.NewExpDecaySample(1028, 0.015)) + resetwaitHist = metrics.NewRegisteredHistogram("blobpool/resetwait", nil, metrics.NewExpDecaySample(1028, 0.015)) + resettimeHist = metrics.NewRegisteredHistogram("blobpool/resettime", nil, metrics.NewExpDecaySample(1028, 0.015)) +) diff --git a/core/txpool/blobpool/priority.go b/core/txpool/blobpool/priority.go new file mode 100644 index 0000000000..18e545c2a8 --- /dev/null +++ b/core/txpool/blobpool/priority.go @@ -0,0 +1,90 @@ +// 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 blobpool + +import ( + "math" + "math/bits" + + "github.com/holiman/uint256" +) + +// log2_1_125 is used in the eviction priority calculation. +var log2_1_125 = math.Log2(1.125) + +// evictionPriority calculates the eviction priority based on the algorithm +// described in the BlobPool docs for a both fee components. +// +// This method takes about 8ns on a very recent laptop CPU, recalculating about +// 125 million transaction priority values per second. +func evictionPriority(basefeeJumps float64, txBasefeeJumps, blobfeeJumps, txBlobfeeJumps float64) int { + var ( + basefeePriority = evictionPriority1D(basefeeJumps, txBasefeeJumps) + blobfeePriority = evictionPriority1D(blobfeeJumps, txBlobfeeJumps) + ) + if basefeePriority < blobfeePriority { + return basefeePriority + } + return blobfeePriority +} + +// evictionPriority1D calculates the eviction priority based on the algorithm +// described in the BlobPool docs for a single fee component. +func evictionPriority1D(basefeeJumps float64, txfeeJumps float64) int { + jumps := txfeeJumps - basefeeJumps + if int(jumps) == 0 { + return 0 // can't log2 0 + } + if jumps < 0 { + return -intLog2(uint(-math.Floor(jumps))) + } + return intLog2(uint(math.Ceil(jumps))) +} + +// 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). +// +// 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 +// be cached. +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 +} + +// intLog2 is a helper to calculate the integral part of a log2 of an unsigned +// integer. It is a very specific calculation that's not particularly useful in +// general, but it's what we need here (it's fast). +func intLog2(n uint) int { + switch { + case n == 0: + panic("log2(0) is undefined") + + case n < 2048: + return bits.UintSize - bits.LeadingZeros(n) - 1 + + default: + // The input is log1.125(uint256) = log2(uint256) / log2(1.125). At the + // most extreme, log2(uint256) will be a bit below 257, and the constant + // log2(1.125) ~= 0.17. The larges input thus is ~257 / ~0.17 ~= ~1511. + panic("dynamic fee jump diffs cannot reach this") + } +} diff --git a/core/txpool/blobpool/priority_test.go b/core/txpool/blobpool/priority_test.go new file mode 100644 index 0000000000..4aad919925 --- /dev/null +++ b/core/txpool/blobpool/priority_test.go @@ -0,0 +1,87 @@ +// 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 blobpool + +import ( + "testing" + + "github.com/holiman/uint256" +) + +// Tests that the priority fees are calculated correctly as the log2 of the fee +// jumps needed to go from the base fee to the tx's fee cap. +func TestPriorityCalculation(t *testing.T) { + tests := []struct { + basefee uint64 + txfee uint64 + result int + }{ + {basefee: 7, txfee: 10, result: 2}, // 3.02 jumps, 4 ceil, 2 log2 + {basefee: 17_200_000_000, txfee: 17_200_000_000, result: 0}, // 0 jumps, special case 0 log2 + {basefee: 9_853_941_692, txfee: 11_085_092_510, result: 0}, // 0.99 jumps, 1 ceil, 0 log2 + {basefee: 11_544_106_391, txfee: 10_356_781_100, result: 0}, // -0.92 jumps, -1 floor, 0 log2 + {basefee: 17_200_000_000, txfee: 7, result: -7}, // -183.57 jumps, -184 floor, -7 log2 + {basefee: 7, txfee: 17_200_000_000, result: 7}, // 183.57 jumps, 184 ceil, 7 log2 + } + for i, tt := range tests { + var ( + baseJumps = dynamicFeeJumps(uint256.NewInt(tt.basefee)) + feeJumps = dynamicFeeJumps(uint256.NewInt(tt.txfee)) + ) + if prio := evictionPriority1D(baseJumps, feeJumps); prio != tt.result { + t.Errorf("test %d priority mismatch: have %d, want %d", i, prio, tt.result) + } + } +} + +// Benchmarks how many dynamic fee jump values can be done. +func BenchmarkDynamicFeeJumpCalculation(b *testing.B) { + fees := make([]*uint256.Int, b.N) + for i := 0; i < b.N; i++ { + fees[i] = uint256.NewInt(rand.Uint64()) + } + b.ResetTimer() + b.ReportAllocs() + for i := 0; i < b.N; i++ { + dynamicFeeJumps(fees[i]) + } +} + +// Benchmarks how many priority recalculations can be done. +func BenchmarkPriorityCalculation(b *testing.B) { + // The basefee and blob fee is constant for all transactions across a block, + // so we can assume theit absolute jump counts can be pre-computed. + basefee := uint256.NewInt(17_200_000_000) // 17.2 Gwei is the 22.03.2023 zero-emission basefee, random number + blobfee := uint256.NewInt(123_456_789_000) // Completely random, no idea what this will be + + basefeeJumps := dynamicFeeJumps(basefee) + blobfeeJumps := dynamicFeeJumps(blobfee) + + // The transaction's fee cap and blob fee cap are constant across the life + // of the transaction, so we can pre-calculate and cache them. + txBasefeeJumps := make([]float64, b.N) + txBlobfeeJumps := make([]float64, b.N) + for i := 0; i < b.N; i++ { + txBasefeeJumps[i] = dynamicFeeJumps(uint256.NewInt(rand.Uint64())) + txBlobfeeJumps[i] = dynamicFeeJumps(uint256.NewInt(rand.Uint64())) + } + b.ResetTimer() + b.ReportAllocs() + for i := 0; i < b.N; i++ { + evictionPriority(basefeeJumps, txBasefeeJumps[i], blobfeeJumps, txBlobfeeJumps[i]) + } +} diff --git a/core/txpool/blobpool/slotter.go b/core/txpool/blobpool/slotter.go new file mode 100644 index 0000000000..35349c3445 --- /dev/null +++ b/core/txpool/blobpool/slotter.go @@ -0,0 +1,38 @@ +// 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 blobpool + +// newSlotter creates a helper method for the Billy datastore that returns the +// individual shelf sizes used to store transactions in. +// +// The slotter will create shelves for each possible blob count + some tx metadata +// wiggle room, up to the max permitted limits. +// +// The slotter also creates a shelf for 0-blob transactions. Whilst those are not +// allowed in the current protocol, having an empty shelf is not a relevant use +// of resources, but it makes stress testing with junk transactions simpler. +func newSlotter() func() (uint32, bool) { + slotsize := uint32(txAvgSize) + slotsize -= uint32(blobSize) // underflows, it's ok, will overflow back in the first return + + return func() (size uint32, done bool) { + slotsize += blobSize + finished := slotsize > maxBlobsPerTransaction*blobSize+txMaxSize + + return slotsize, finished + } +} diff --git a/core/txpool/blobpool/slotter_test.go b/core/txpool/blobpool/slotter_test.go new file mode 100644 index 0000000000..a7b43b4d22 --- /dev/null +++ b/core/txpool/blobpool/slotter_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 blobpool + +import "testing" + +// Tests that the slotter creates the expected database shelves. +func TestNewSlotter(t *testing.T) { + // Generate the database shelve sizes + slotter := newSlotter() + + var shelves []uint32 + for { + shelf, done := slotter() + shelves = append(shelves, shelf) + if done { + break + } + } + // Compare the database shelves to the expected ones + want := []uint32{ + 0*blobSize + txAvgSize, // 0 blob + some expected tx infos + 1*blobSize + txAvgSize, // 1 blob + some expected tx infos + 2*blobSize + txAvgSize, // 2 blob + some expected tx infos (could be fewer blobs and more tx data) + 3*blobSize + txAvgSize, // 3 blob + some expected tx infos (could be fewer blobs and more tx data) + 4*blobSize + txAvgSize, // 4 blob + some expected tx infos (could be fewer blobs and more tx data) + 5*blobSize + txAvgSize, // 1-6 blobs + unexpectedly large tx infos < 4 blobs + max tx metadata size + 6*blobSize + txAvgSize, // 1-6 blobs + unexpectedly large tx infos < 4 blobs + max tx metadata size + 7*blobSize + txAvgSize, // 1-6 blobs + unexpectedly large tx infos < 4 blobs + max tx metadata size + 8*blobSize + txAvgSize, // 1-6 blobs + unexpectedly large tx infos < 4 blobs + max tx metadata size + 9*blobSize + txAvgSize, // 1-6 blobs + unexpectedly large tx infos < 4 blobs + max tx metadata size + 10*blobSize + txAvgSize, // 1-6 blobs + unexpectedly large tx infos < 4 blobs + max tx metadata size + 11*blobSize + txAvgSize, // 1-6 blobs + unexpectedly large tx infos < 4 blobs + max tx metadata size + 12*blobSize + txAvgSize, // 1-6 blobs + unexpectedly large tx infos < 4 blobs + max tx metadata size + 13*blobSize + txAvgSize, // 1-6 blobs + unexpectedly large tx infos < 4 blobs + max tx metadata size + 14*blobSize + txAvgSize, // 1-6 blobs + unexpectedly large tx infos >= 4 blobs + max tx metadata size + } + if len(shelves) != len(want) { + t.Errorf("shelves count mismatch: have %d, want %d", len(shelves), len(want)) + } + for i := 0; i < len(shelves) && i < len(want); i++ { + if shelves[i] != want[i] { + t.Errorf("shelf %d mismatch: have %d, want %d", i, shelves[i], want[i]) + } + } +} diff --git a/core/txpool/errors.go b/core/txpool/errors.go new file mode 100644 index 0000000000..bc26550f78 --- /dev/null +++ b/core/txpool/errors.go @@ -0,0 +1,57 @@ +// Copyright 2014 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package txpool + +import "errors" + +var ( + // ErrAlreadyKnown is returned if the transactions is already contained + // within the pool. + ErrAlreadyKnown = errors.New("already known") + + // ErrInvalidSender is returned if the transaction contains an invalid signature. + ErrInvalidSender = errors.New("invalid sender") + + // ErrUnderpriced is returned if a transaction's gas price is below the minimum + // configured for the transaction pool. + ErrUnderpriced = errors.New("transaction underpriced") + + // ErrReplaceUnderpriced is returned if a transaction is attempted to be replaced + // with a different one without the required price bump. + ErrReplaceUnderpriced = errors.New("replacement transaction underpriced") + + // ErrAccountLimitExceeded is returned if a transaction would exceed the number + // allowed by a pool for a single account. + ErrAccountLimitExceeded = errors.New("account limit exceeded") + + // ErrGasLimit is returned if a transaction's requested gas limit exceeds the + // maximum allowance of the current block. + ErrGasLimit = errors.New("exceeds block gas limit") + + // ErrNegativeValue is a sanity error to ensure no one is able to specify a + // transaction with a negative value. + ErrNegativeValue = errors.New("negative value") + + // ErrOversizedData is returned if the input data of a transaction is greater + // than some meaningful limit a user might use. This is not a consensus error + // making the transaction invalid, rather a DOS protection. + ErrOversizedData = errors.New("oversized data") + + // ErrFutureReplacePending is returned if a future transaction replaces a pending + // transaction. Future transactions should only be able to replace other future transactions. + ErrFutureReplacePending = errors.New("future transaction tries to replace pending") +) diff --git a/core/txpool/journal.go b/core/txpool/legacypool/journal.go similarity index 99% rename from core/txpool/journal.go rename to core/txpool/legacypool/journal.go index 1b330b0c3c..f04ab8fc14 100644 --- a/core/txpool/journal.go +++ b/core/txpool/legacypool/journal.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 txpool +package legacypool import ( "errors" diff --git a/core/txpool/legacypool/legacypool.go b/core/txpool/legacypool/legacypool.go new file mode 100644 index 0000000000..00e326c4b8 --- /dev/null +++ b/core/txpool/legacypool/legacypool.go @@ -0,0 +1,1931 @@ +// Copyright 2014 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +// Package legacypool implements the normal EVM execution transaction pool. +package legacypool + +import ( + "errors" + "math" + "math/big" + "sort" + "sync" + "sync/atomic" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/prque" + "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/txpool" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/metrics" + "github.com/ethereum/go-ethereum/params" +) + +const ( + // txSlotSize is used to calculate how many data slots a single transaction + // takes up based on its size. The slots are used as DoS protection, ensuring + // that validating a new transaction remains a constant operation (in reality + // O(maxslots), where max slots are 4 currently). + txSlotSize = 32 * 1024 + + // txMaxSize is the maximum size a single transaction can have. This field has + // non-trivial consequences: larger transactions are significantly harder and + // more expensive to propagate; larger transactions also take more resources + // to validate whether they fit into the pool or not. + txMaxSize = 4 * txSlotSize // 128KB +) + +var ( + // ErrAlreadyKnown is returned if the transactions is already contained + // within the pool. + ErrAlreadyKnown = errors.New("already known") + + // ErrTxPoolOverflow is returned if the transaction pool is full and can't accept + // another remote transaction. + ErrTxPoolOverflow = errors.New("txpool is full") +) + +var ( + evictionInterval = time.Minute // Time interval to check for evictable transactions + statsReportInterval = 8 * time.Second // Time interval to report transaction pool stats +) + +var ( + // Metrics for the pending pool + pendingDiscardMeter = metrics.NewRegisteredMeter("txpool/pending/discard", nil) + pendingReplaceMeter = metrics.NewRegisteredMeter("txpool/pending/replace", nil) + pendingRateLimitMeter = metrics.NewRegisteredMeter("txpool/pending/ratelimit", nil) // Dropped due to rate limiting + pendingNofundsMeter = metrics.NewRegisteredMeter("txpool/pending/nofunds", nil) // Dropped due to out-of-funds + + // Metrics for the queued pool + queuedDiscardMeter = metrics.NewRegisteredMeter("txpool/queued/discard", nil) + queuedReplaceMeter = metrics.NewRegisteredMeter("txpool/queued/replace", nil) + queuedRateLimitMeter = metrics.NewRegisteredMeter("txpool/queued/ratelimit", nil) // Dropped due to rate limiting + queuedNofundsMeter = metrics.NewRegisteredMeter("txpool/queued/nofunds", nil) // Dropped due to out-of-funds + queuedEvictionMeter = metrics.NewRegisteredMeter("txpool/queued/eviction", nil) // Dropped due to lifetime + + // General tx metrics + knownTxMeter = metrics.NewRegisteredMeter("txpool/known", nil) + validTxMeter = metrics.NewRegisteredMeter("txpool/valid", nil) + invalidTxMeter = metrics.NewRegisteredMeter("txpool/invalid", nil) + underpricedTxMeter = metrics.NewRegisteredMeter("txpool/underpriced", nil) + overflowedTxMeter = metrics.NewRegisteredMeter("txpool/overflowed", nil) + + // throttleTxMeter counts how many transactions are rejected due to too-many-changes between + // txpool reorgs. + throttleTxMeter = metrics.NewRegisteredMeter("txpool/throttle", nil) + // reorgDurationTimer measures how long time a txpool reorg takes. + reorgDurationTimer = metrics.NewRegisteredTimer("txpool/reorgtime", nil) + // dropBetweenReorgHistogram counts how many drops we experience between two reorg runs. It is expected + // that this number is pretty low, since txpool reorgs happen very frequently. + dropBetweenReorgHistogram = metrics.NewRegisteredHistogram("txpool/dropbetweenreorg", nil, metrics.NewExpDecaySample(1028, 0.015)) + + pendingGauge = metrics.NewRegisteredGauge("txpool/pending", nil) + queuedGauge = metrics.NewRegisteredGauge("txpool/queued", nil) + localGauge = metrics.NewRegisteredGauge("txpool/local", nil) + slotsGauge = metrics.NewRegisteredGauge("txpool/slots", nil) + + reheapTimer = metrics.NewRegisteredTimer("txpool/reheap", nil) +) + +// BlockChain defines the minimal set of methods needed to back a tx pool with +// a chain. Exists to allow mocking the live chain out of tests. +type BlockChain interface { + // Config retrieves the chain's fork configuration. + Config() *params.ChainConfig + + // CurrentBlock returns the current head of the chain. + CurrentBlock() *types.Header + + // GetBlock retrieves a specific block, used during pool resets. + GetBlock(hash common.Hash, number uint64) *types.Block + + // StateAt returns a state database for a given root hash (generally the head). + StateAt(root common.Hash) (*state.StateDB, error) +} + +// Config are the configuration parameters of the transaction pool. +type Config struct { + Locals []common.Address // Addresses that should be treated by default as local + NoLocals bool // Whether local transaction handling should be disabled + Journal string // Journal of local transactions to survive node restarts + Rejournal time.Duration // Time interval to regenerate the local transaction journal + + PriceLimit uint64 // Minimum gas price to enforce for acceptance into the pool + PriceBump uint64 // Minimum price bump percentage to replace an already existing transaction (nonce) + + AccountSlots uint64 // Number of executable transaction slots guaranteed per account + GlobalSlots uint64 // Maximum number of executable transaction slots for all accounts + AccountQueue uint64 // Maximum number of non-executable transaction slots permitted per account + GlobalQueue uint64 // Maximum number of non-executable transaction slots for all accounts + + Lifetime time.Duration // Maximum amount of time non-executable transaction are queued +} + +// DefaultConfig contains the default configurations for the transaction pool. +var DefaultConfig = Config{ + Journal: "transactions.rlp", + Rejournal: time.Hour, + + PriceLimit: 1, + PriceBump: 10, + + AccountSlots: 16, + GlobalSlots: 4096 + 1024, // urgent + floating queue capacity with 4:1 ratio + AccountQueue: 64, + GlobalQueue: 1024, + + Lifetime: 3 * time.Hour, +} + +// sanitize checks the provided user configurations and changes anything that's +// unreasonable or unworkable. +func (config *Config) sanitize() Config { + conf := *config + if conf.Rejournal < time.Second { + log.Warn("Sanitizing invalid txpool journal time", "provided", conf.Rejournal, "updated", time.Second) + conf.Rejournal = time.Second + } + if conf.PriceLimit < 1 { + log.Warn("Sanitizing invalid txpool price limit", "provided", conf.PriceLimit, "updated", DefaultConfig.PriceLimit) + conf.PriceLimit = DefaultConfig.PriceLimit + } + if conf.PriceBump < 1 { + log.Warn("Sanitizing invalid txpool price bump", "provided", conf.PriceBump, "updated", DefaultConfig.PriceBump) + conf.PriceBump = DefaultConfig.PriceBump + } + if conf.AccountSlots < 1 { + log.Warn("Sanitizing invalid txpool account slots", "provided", conf.AccountSlots, "updated", DefaultConfig.AccountSlots) + conf.AccountSlots = DefaultConfig.AccountSlots + } + if conf.GlobalSlots < 1 { + log.Warn("Sanitizing invalid txpool global slots", "provided", conf.GlobalSlots, "updated", DefaultConfig.GlobalSlots) + conf.GlobalSlots = DefaultConfig.GlobalSlots + } + if conf.AccountQueue < 1 { + log.Warn("Sanitizing invalid txpool account queue", "provided", conf.AccountQueue, "updated", DefaultConfig.AccountQueue) + conf.AccountQueue = DefaultConfig.AccountQueue + } + if conf.GlobalQueue < 1 { + log.Warn("Sanitizing invalid txpool global queue", "provided", conf.GlobalQueue, "updated", DefaultConfig.GlobalQueue) + conf.GlobalQueue = DefaultConfig.GlobalQueue + } + if conf.Lifetime < 1 { + log.Warn("Sanitizing invalid txpool lifetime", "provided", conf.Lifetime, "updated", DefaultConfig.Lifetime) + conf.Lifetime = DefaultConfig.Lifetime + } + return conf +} + +// LegacyPool contains all currently known transactions. Transactions +// enter the pool when they are received from the network or submitted +// locally. They exit the pool when they are included in the blockchain. +// +// The pool separates processable transactions (which can be applied to the +// current state) and future transactions. Transactions move between those +// two states over time as they are received and processed. +type LegacyPool struct { + config Config + chainconfig *params.ChainConfig + chain BlockChain + gasTip atomic.Pointer[big.Int] + txFeed event.Feed + scope event.SubscriptionScope + signer types.Signer + mu sync.RWMutex + + currentHead atomic.Pointer[types.Header] // Current head of the blockchain + currentState *state.StateDB // Current state in the blockchain head + pendingNonces *noncer // Pending state tracking virtual nonces + + locals *accountSet // Set of local transaction to exempt from eviction rules + journal *journal // Journal of local transaction to back up to disk + + reserve txpool.AddressReserver // Address reserver to ensure exclusivity across subpools + pending map[common.Address]*list // All currently processable transactions + queue map[common.Address]*list // Queued but non-processable transactions + beats map[common.Address]time.Time // Last heartbeat from each known account + all *lookup // All transactions to allow lookups + priced *pricedList // All transactions sorted by price + + reqResetCh chan *txpoolResetRequest + reqPromoteCh chan *accountSet + queueTxEventCh chan *types.Transaction + reorgDoneCh chan chan struct{} + reorgShutdownCh chan struct{} // requests shutdown of scheduleReorgLoop + wg sync.WaitGroup // tracks loop, scheduleReorgLoop + initDoneCh chan struct{} // is closed once the pool is initialized (for tests) + + changesSinceReorg int // A counter for how many drops we've performed in-between reorg. +} + +type txpoolResetRequest struct { + oldHead, newHead *types.Header +} + +// New creates a new transaction pool to gather, sort and filter inbound +// transactions from the network. +func New(config Config, chain BlockChain) *LegacyPool { + // Sanitize the input to ensure no vulnerable gas prices are set + config = (&config).sanitize() + + // Create the transaction pool with its initial settings + pool := &LegacyPool{ + config: config, + chain: chain, + chainconfig: chain.Config(), + signer: types.LatestSigner(chain.Config()), + pending: make(map[common.Address]*list), + queue: make(map[common.Address]*list), + beats: make(map[common.Address]time.Time), + all: newLookup(), + reqResetCh: make(chan *txpoolResetRequest), + reqPromoteCh: make(chan *accountSet), + queueTxEventCh: make(chan *types.Transaction), + reorgDoneCh: make(chan chan struct{}), + reorgShutdownCh: make(chan struct{}), + initDoneCh: make(chan struct{}), + } + pool.locals = newAccountSet(pool.signer) + for _, addr := range config.Locals { + log.Info("Setting new local account", "address", addr) + pool.locals.add(addr) + } + pool.priced = newPricedList(pool.all) + + if !config.NoLocals && config.Journal != "" { + pool.journal = newTxJournal(config.Journal) + } + return pool +} + +// Filter returns whether the given transaction can be consumed by the legacy +// pool, specifically, whether it is a Legacy, AccessList or Dynamic transaction. +func (pool *LegacyPool) Filter(tx *types.Transaction) bool { + switch tx.Type() { + case types.LegacyTxType, types.AccessListTxType, types.DynamicFeeTxType: + return true + default: + return false + } +} + +// Init sets the gas price needed to keep a transaction in the pool and the chain +// head to allow balance / nonce checks. The transaction journal will be loaded +// from disk and filtered based on the provided starting settings. The internal +// goroutines will be spun up and the pool deemed operational afterwards. +func (pool *LegacyPool) Init(gasTip *big.Int, head *types.Header, reserve txpool.AddressReserver) error { + // Set the address reserver to request exclusive access to pooled accounts + pool.reserve = reserve + + // Set the basic pool parameters + pool.gasTip.Store(gasTip) + pool.reset(nil, head) + + // Start the reorg loop early, so it can handle requests generated during + // journal loading. + pool.wg.Add(1) + go pool.scheduleReorgLoop() + + // If local transactions and journaling is enabled, load from disk + if pool.journal != nil { + if err := pool.journal.load(pool.addLocals); err != nil { + log.Warn("Failed to load transaction journal", "err", err) + } + if err := pool.journal.rotate(pool.local()); err != nil { + log.Warn("Failed to rotate transaction journal", "err", err) + } + } + pool.wg.Add(1) + go pool.loop() + return nil +} + +// loop is the transaction pool's main event loop, waiting for and reacting to +// outside blockchain events as well as for various reporting and transaction +// eviction events. +func (pool *LegacyPool) loop() { + defer pool.wg.Done() + + var ( + prevPending, prevQueued, prevStales int + + // Start the stats reporting and transaction eviction tickers + report = time.NewTicker(statsReportInterval) + evict = time.NewTicker(evictionInterval) + journal = time.NewTicker(pool.config.Rejournal) + ) + defer report.Stop() + defer evict.Stop() + defer journal.Stop() + + // Notify tests that the init phase is done + close(pool.initDoneCh) + for { + select { + // Handle pool shutdown + case <-pool.reorgShutdownCh: + return + + // Handle stats reporting ticks + case <-report.C: + pool.mu.RLock() + pending, queued := pool.stats() + pool.mu.RUnlock() + stales := int(pool.priced.stales.Load()) + + if pending != prevPending || queued != prevQueued || stales != prevStales { + log.Debug("Transaction pool status report", "executable", pending, "queued", queued, "stales", stales) + prevPending, prevQueued, prevStales = pending, queued, stales + } + + // Handle inactive account transaction eviction + case <-evict.C: + pool.mu.Lock() + for addr := range pool.queue { + // Skip local transactions from the eviction mechanism + if pool.locals.contains(addr) { + continue + } + // Any non-locals old enough should be removed + if time.Since(pool.beats[addr]) > pool.config.Lifetime { + list := pool.queue[addr].Flatten() + for _, tx := range list { + pool.removeTx(tx.Hash(), true, true) + } + queuedEvictionMeter.Mark(int64(len(list))) + } + } + pool.mu.Unlock() + + // Handle local transaction journal rotation + case <-journal.C: + if pool.journal != nil { + pool.mu.Lock() + if err := pool.journal.rotate(pool.local()); err != nil { + log.Warn("Failed to rotate local tx journal", "err", err) + } + pool.mu.Unlock() + } + } + } +} + +// Close terminates the transaction pool. +func (pool *LegacyPool) Close() error { + // Unsubscribe all subscriptions registered from txpool + pool.scope.Close() + + // Terminate the pool reorger and return + close(pool.reorgShutdownCh) + pool.wg.Wait() + + if pool.journal != nil { + pool.journal.close() + } + log.Info("Transaction pool stopped") + return nil +} + +// Reset implements txpool.SubPool, allowing the legacy pool's internal state to be +// kept in sync with the main transacion pool's internal state. +func (pool *LegacyPool) Reset(oldHead, newHead *types.Header) { + wait := pool.requestReset(oldHead, newHead) + <-wait +} + +// SubscribeTransactions registers a subscription of NewTxsEvent and +// starts sending event to the given channel. +func (pool *LegacyPool) SubscribeTransactions(ch chan<- core.NewTxsEvent) event.Subscription { + return pool.scope.Track(pool.txFeed.Subscribe(ch)) +} + +// 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) { + pool.mu.Lock() + defer pool.mu.Unlock() + + old := pool.gasTip.Load() + pool.gasTip.Store(new(big.Int).Set(tip)) + + // If the min miner fee increased, remove transactions below the new threshold + if tip.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)) + } + log.Info("Legacy pool tip threshold updated", "tip", tip) +} + +// 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 { + pool.mu.RLock() + defer pool.mu.RUnlock() + + return pool.pendingNonces.get(addr) +} + +// Stats retrieves the current pool stats, namely the number of pending and the +// number of queued (non-executable) transactions. +func (pool *LegacyPool) Stats() (int, int) { + pool.mu.RLock() + defer pool.mu.RUnlock() + + return pool.stats() +} + +// stats retrieves the current pool stats, namely the number of pending and the +// number of queued (non-executable) transactions. +func (pool *LegacyPool) stats() (int, int) { + pending := 0 + for _, list := range pool.pending { + pending += list.Len() + } + queued := 0 + for _, list := range pool.queue { + queued += list.Len() + } + return pending, queued +} + +// Content retrieves the data content of the transaction pool, returning all the +// pending as well as queued transactions, grouped by account and sorted by nonce. +func (pool *LegacyPool) Content() (map[common.Address][]*types.Transaction, map[common.Address][]*types.Transaction) { + pool.mu.Lock() + defer pool.mu.Unlock() + + pending := make(map[common.Address][]*types.Transaction, len(pool.pending)) + for addr, list := range pool.pending { + pending[addr] = list.Flatten() + } + queued := make(map[common.Address][]*types.Transaction, len(pool.queue)) + for addr, list := range pool.queue { + queued[addr] = list.Flatten() + } + return pending, queued +} + +// ContentFrom retrieves the data content of the transaction pool, returning the +// pending as well as queued transactions of this address, grouped by nonce. +func (pool *LegacyPool) ContentFrom(addr common.Address) ([]*types.Transaction, []*types.Transaction) { + pool.mu.RLock() + defer pool.mu.RUnlock() + + var pending []*types.Transaction + if list, ok := pool.pending[addr]; ok { + pending = list.Flatten() + } + var queued []*types.Transaction + if list, ok := pool.queue[addr]; ok { + queued = list.Flatten() + } + return pending, queued +} + +// Pending retrieves all currently processable transactions, grouped by origin +// account and sorted by nonce. The returned transaction set is a copy and can be +// freely modified by calling code. +// +// The enforceTips parameter can be used to do an extra filtering on the pending +// transactions and only return those whose **effective** tip is large enough in +// the next pending execution environment. +func (pool *LegacyPool) Pending(enforceTips bool) map[common.Address][]*txpool.LazyTransaction { + pool.mu.Lock() + defer pool.mu.Unlock() + + pending := make(map[common.Address][]*txpool.LazyTransaction, len(pool.pending)) + for addr, list := range pool.pending { + txs := list.Flatten() + + // If the miner requests tip enforcement, cap the lists now + if enforceTips && !pool.locals.contains(addr) { + for i, tx := range txs { + if tx.EffectiveGasTipIntCmp(pool.gasTip.Load(), pool.priced.urgent.baseFee) < 0 { + txs = txs[:i] + break + } + } + } + if len(txs) > 0 { + lazies := make([]*txpool.LazyTransaction, len(txs)) + for i := 0; i < len(txs); i++ { + lazies[i] = &txpool.LazyTransaction{ + Pool: pool, + Hash: txs[i].Hash(), + Tx: txs[i], + Time: txs[i].Time(), + GasFeeCap: txs[i].GasFeeCap(), + GasTipCap: txs[i].GasTipCap(), + } + } + pending[addr] = lazies + } + } + return pending +} + +// Locals retrieves the accounts currently considered local by the pool. +func (pool *LegacyPool) Locals() []common.Address { + pool.mu.Lock() + defer pool.mu.Unlock() + + return pool.locals.flatten() +} + +// local retrieves all currently known local transactions, grouped by origin +// account and sorted by nonce. The returned transaction set is a copy and can be +// freely modified by calling code. +func (pool *LegacyPool) local() map[common.Address]types.Transactions { + txs := make(map[common.Address]types.Transactions) + for addr := range pool.locals.accounts { + if pending := pool.pending[addr]; pending != nil { + txs[addr] = append(txs[addr], pending.Flatten()...) + } + if queued := pool.queue[addr]; queued != nil { + txs[addr] = append(txs[addr], queued.Flatten()...) + } + } + return txs +} + +// validateTxBasics checks whether a transaction is valid according to the consensus +// rules, but does not check state-dependent validation such as sufficient balance. +// This check is meant as an early check which only needs to be performed once, +// and does not require the pool mutex to be held. +func (pool *LegacyPool) validateTxBasics(tx *types.Transaction, local bool) error { + opts := &txpool.ValidationOptions{ + Config: pool.chainconfig, + Accept: 0 | + 1< pool.config.GlobalSlots+pool.config.GlobalQueue { + // If the new transaction is underpriced, don't accept it + if !isLocal && pool.priced.Underpriced(tx) { + log.Trace("Discarding underpriced transaction", "hash", hash, "gasTipCap", tx.GasTipCap(), "gasFeeCap", tx.GasFeeCap()) + underpricedTxMeter.Mark(1) + return false, txpool.ErrUnderpriced + } + + // We're about to replace a transaction. The reorg does a more thorough + // analysis of what to remove and how, but it runs async. We don't want to + // do too many replacements between reorg-runs, so we cap the number of + // replacements to 25% of the slots + if pool.changesSinceReorg > int(pool.config.GlobalSlots/4) { + throttleTxMeter.Mark(1) + return false, ErrTxPoolOverflow + } + + // New transaction is better than our worse ones, make room for it. + // If it's a local transaction, forcibly discard all available transactions. + // Otherwise if we can't make enough room for new one, abort the operation. + drop, success := pool.priced.Discard(pool.all.Slots()-int(pool.config.GlobalSlots+pool.config.GlobalQueue)+numSlots(tx), isLocal) + + // Special case, we still can't make the room for the new remote one. + if !isLocal && !success { + log.Trace("Discarding overflown transaction", "hash", hash) + overflowedTxMeter.Mark(1) + return false, ErrTxPoolOverflow + } + + // If the new transaction is a future transaction it should never churn pending transactions + if !isLocal && pool.isGapped(from, tx) { + var replacesPending bool + for _, dropTx := range drop { + dropSender, _ := types.Sender(pool.signer, dropTx) + if list := pool.pending[dropSender]; list != nil && list.Contains(dropTx.Nonce()) { + replacesPending = true + break + } + } + // Add all transactions back to the priced queue + if replacesPending { + for _, dropTx := range drop { + pool.priced.Put(dropTx, false) + } + log.Trace("Discarding future transaction replacing pending tx", "hash", hash) + return false, txpool.ErrFutureReplacePending + } + } + + // Kick out the underpriced remote transactions. + for _, tx := range drop { + log.Trace("Discarding freshly underpriced transaction", "hash", tx.Hash(), "gasTipCap", tx.GasTipCap(), "gasFeeCap", tx.GasFeeCap()) + underpricedTxMeter.Mark(1) + + sender, _ := types.Sender(pool.signer, tx) + dropped := pool.removeTx(tx.Hash(), false, sender != from) // Don't unreserve the sender of the tx being added if last from the acc + + pool.changesSinceReorg += dropped + } + } + + // Try to replace an existing transaction in the pending pool + if list := pool.pending[from]; list != nil && list.Contains(tx.Nonce()) { + // Nonce already pending, check if required price bump is met + inserted, old := list.Add(tx, pool.config.PriceBump) + if !inserted { + pendingDiscardMeter.Mark(1) + return false, txpool.ErrReplaceUnderpriced + } + // New transaction is better, replace old one + if old != nil { + pool.all.Remove(old.Hash()) + pool.priced.Removed(1) + pendingReplaceMeter.Mark(1) + } + pool.all.Add(tx, isLocal) + pool.priced.Put(tx, isLocal) + pool.journalTx(from, tx) + pool.queueTxEvent(tx) + log.Trace("Pooled new executable transaction", "hash", hash, "from", from, "to", tx.To()) + + // Successful promotion, bump the heartbeat + pool.beats[from] = time.Now() + return old != nil, nil + } + // New transaction isn't replacing a pending one, push into queue + replaced, err = pool.enqueueTx(hash, tx, isLocal, true) + if err != nil { + return false, err + } + // Mark local addresses and journal local transactions + if local && !pool.locals.contains(from) { + log.Info("Setting new local account", "address", from) + pool.locals.add(from) + pool.priced.Removed(pool.all.RemoteToLocals(pool.locals)) // Migrate the remotes if it's marked as local first time. + } + if isLocal { + localGauge.Inc(1) + } + pool.journalTx(from, tx) + + log.Trace("Pooled new future transaction", "hash", hash, "from", from, "to", tx.To()) + return replaced, nil +} + +// isGapped reports whether the given transaction is immediately executable. +func (pool *LegacyPool) isGapped(from common.Address, tx *types.Transaction) bool { + // Short circuit if transaction falls within the scope of the pending list + // or matches the next pending nonce which can be promoted as an executable + // transaction afterwards. Note, the tx staleness is already checked in + // 'validateTx' function previously. + next := pool.pendingNonces.get(from) + if tx.Nonce() <= next { + return false + } + // The transaction has a nonce gap with pending list, it's only considered + // as executable if transactions in queue can fill up the nonce gap. + queue, ok := pool.queue[from] + if !ok { + return true + } + for nonce := next; nonce < tx.Nonce(); nonce++ { + if !queue.Contains(nonce) { + return true // txs in queue can't fill up the nonce gap + } + } + return false +} + +// enqueueTx inserts a new transaction into the non-executable transaction queue. +// +// Note, this method assumes the pool lock is held! +func (pool *LegacyPool) enqueueTx(hash common.Hash, tx *types.Transaction, local bool, addAll bool) (bool, error) { + // Try to insert the transaction into the future queue + from, _ := types.Sender(pool.signer, tx) // already validated + if pool.queue[from] == nil { + pool.queue[from] = newList(false) + } + inserted, old := pool.queue[from].Add(tx, pool.config.PriceBump) + if !inserted { + // An older transaction was better, discard this + queuedDiscardMeter.Mark(1) + return false, txpool.ErrReplaceUnderpriced + } + // Discard any previous transaction and mark this + if old != nil { + pool.all.Remove(old.Hash()) + pool.priced.Removed(1) + queuedReplaceMeter.Mark(1) + } else { + // Nothing was replaced, bump the queued counter + queuedGauge.Inc(1) + } + // If the transaction isn't in lookup set but it's expected to be there, + // show the error log. + if pool.all.Get(hash) == nil && !addAll { + log.Error("Missing transaction in lookup set, please report the issue", "hash", hash) + } + if addAll { + pool.all.Add(tx, local) + pool.priced.Put(tx, local) + } + // If we never record the heartbeat, do it right now. + if _, exist := pool.beats[from]; !exist { + pool.beats[from] = time.Now() + } + return old != nil, nil +} + +// journalTx adds the specified transaction to the local disk journal if it is +// deemed to have been sent from a local account. +func (pool *LegacyPool) journalTx(from common.Address, tx *types.Transaction) { + // Only journal if it's enabled and the transaction is local + if pool.journal == nil || !pool.locals.contains(from) { + return + } + if err := pool.journal.insert(tx); err != nil { + log.Warn("Failed to journal local transaction", "err", err) + } +} + +// promoteTx adds a transaction to the pending (processable) list of transactions +// and returns whether it was inserted or an older was better. +// +// Note, this method assumes the pool lock is held! +func (pool *LegacyPool) promoteTx(addr common.Address, hash common.Hash, tx *types.Transaction) bool { + // Try to insert the transaction into the pending queue + if pool.pending[addr] == nil { + pool.pending[addr] = newList(true) + } + list := pool.pending[addr] + + inserted, old := list.Add(tx, pool.config.PriceBump) + if !inserted { + // An older transaction was better, discard this + pool.all.Remove(hash) + pool.priced.Removed(1) + pendingDiscardMeter.Mark(1) + return false + } + // Otherwise discard any previous transaction and mark this + if old != nil { + pool.all.Remove(old.Hash()) + pool.priced.Removed(1) + pendingReplaceMeter.Mark(1) + } else { + // Nothing was replaced, bump the pending counter + pendingGauge.Inc(1) + } + // Set the potentially new pending nonce and notify any subsystems of the new tx + pool.pendingNonces.set(addr, tx.Nonce()+1) + + // Successful promotion, bump the heartbeat + pool.beats[addr] = time.Now() + return true +} + +// addLocals enqueues a batch of transactions into the pool if they are valid, marking the +// senders as a local ones, ensuring they go around the local pricing constraints. +// +// This method is used to add transactions from the RPC API and performs synchronous pool +// reorganization and event propagation. +func (pool *LegacyPool) addLocals(txs []*types.Transaction) []error { + return pool.Add(txs, !pool.config.NoLocals, true) +} + +// addLocal enqueues a single local transaction into the pool if it is valid. This is +// a convenience wrapper around addLocals. +func (pool *LegacyPool) addLocal(tx *types.Transaction) error { + errs := pool.addLocals([]*types.Transaction{tx}) + return errs[0] +} + +// addRemotes enqueues a batch of transactions into the pool if they are valid. If the +// senders are not among the locally tracked ones, full pricing constraints will apply. +// +// This method is used to add transactions from the p2p network and does not wait for pool +// reorganization and internal event propagation. +func (pool *LegacyPool) addRemotes(txs []*types.Transaction) []error { + return pool.Add(txs, false, false) +} + +// addRemote enqueues a single transaction into the pool if it is valid. This is a convenience +// wrapper around addRemotes. +func (pool *LegacyPool) addRemote(tx *types.Transaction) error { + errs := pool.addRemotes([]*types.Transaction{tx}) + return errs[0] +} + +// addRemotesSync is like addRemotes, but waits for pool reorganization. Tests use this method. +func (pool *LegacyPool) addRemotesSync(txs []*types.Transaction) []error { + return pool.Add(txs, false, true) +} + +// This is like addRemotes with a single transaction, but waits for pool reorganization. Tests use this method. +func (pool *LegacyPool) addRemoteSync(tx *types.Transaction) error { + return pool.Add([]*types.Transaction{tx}, false, true)[0] +} + +// Add enqueues a batch of transactions into the pool if they are valid. Depending +// on the local flag, full pricing contraints will or will not be applied. +// +// If sync is set, the method will block until all internal maintenance related +// to the add is finished. Only use this during tests for determinism! +func (pool *LegacyPool) Add(txs []*types.Transaction, local, sync bool) []error { + // Filter out known ones without obtaining the pool lock or recovering signatures + var ( + errs = make([]error, len(txs)) + news = make([]*types.Transaction, 0, len(txs)) + ) + for i, tx := range txs { + // If the transaction is known, pre-set the error slot + if pool.all.Get(tx.Hash()) != nil { + errs[i] = ErrAlreadyKnown + knownTxMeter.Mark(1) + continue + } + // Exclude transactions with basic errors, e.g invalid signatures and + // insufficient intrinsic gas as soon as possible and cache senders + // in transactions before obtaining lock + if err := pool.validateTxBasics(tx, local); err != nil { + errs[i] = err + invalidTxMeter.Mark(1) + continue + } + // Accumulate all unknown transactions for deeper processing + news = append(news, tx) + } + if len(news) == 0 { + return errs + } + + // Process all the new transaction and merge any errors into the original slice + pool.mu.Lock() + newErrs, dirtyAddrs := pool.addTxsLocked(news, local) + pool.mu.Unlock() + + var nilSlot = 0 + for _, err := range newErrs { + for errs[nilSlot] != nil { + nilSlot++ + } + errs[nilSlot] = err + nilSlot++ + } + // Reorg the pool internals if needed and return + done := pool.requestPromoteExecutables(dirtyAddrs) + if sync { + <-done + } + return errs +} + +// addTxsLocked attempts to queue a batch of transactions if they are valid. +// The transaction pool lock must be held. +func (pool *LegacyPool) addTxsLocked(txs []*types.Transaction, local bool) ([]error, *accountSet) { + dirty := newAccountSet(pool.signer) + errs := make([]error, len(txs)) + for i, tx := range txs { + replaced, err := pool.add(tx, local) + errs[i] = err + if err == nil && !replaced { + dirty.addTx(tx) + } + } + validTxMeter.Mark(int64(len(dirty.accounts))) + return errs, dirty +} + +// Status returns the status (unknown/pending/queued) of a batch of transactions +// identified by their hashes. +func (pool *LegacyPool) Status(hash common.Hash) txpool.TxStatus { + tx := pool.get(hash) + if tx == nil { + return txpool.TxStatusUnknown + } + from, _ := types.Sender(pool.signer, tx) // already validated + + pool.mu.RLock() + defer pool.mu.RUnlock() + + if txList := pool.pending[from]; txList != nil && txList.txs.items[tx.Nonce()] != nil { + return txpool.TxStatusPending + } else if txList := pool.queue[from]; txList != nil && txList.txs.items[tx.Nonce()] != nil { + return txpool.TxStatusQueued + } + return txpool.TxStatusUnknown +} + +// Get returns a transaction if it is contained in the pool and nil otherwise. +func (pool *LegacyPool) Get(hash common.Hash) *types.Transaction { + tx := pool.get(hash) + if tx == nil { + return nil + } + return tx +} + +// get returns a transaction if it is contained in the pool and nil otherwise. +func (pool *LegacyPool) get(hash common.Hash) *types.Transaction { + return pool.all.Get(hash) +} + +// Has returns an indicator whether txpool has a transaction cached with the +// given hash. +func (pool *LegacyPool) Has(hash common.Hash) bool { + return pool.all.Get(hash) != nil +} + +// removeTx removes a single transaction from the queue, moving all subsequent +// transactions back to the future queue. +// +// In unreserve is false, the account will not be relinquished to the main txpool +// even if there are no more references to it. This is used to handle a race when +// a tx being added, and it evicts a previously scheduled tx from the same account, +// which could lead to a premature release of the lock. +// +// Returns the number of transactions removed from the pending queue. +func (pool *LegacyPool) removeTx(hash common.Hash, outofbound bool, unreserve bool) int { + // Fetch the transaction we wish to delete + tx := pool.all.Get(hash) + if tx == nil { + return 0 + } + addr, _ := types.Sender(pool.signer, tx) // already validated during insertion + + // If after deletion there are no more transactions belonging to this account, + // relinquish the address reservation. It's a bit convoluted do this, via a + // defer, but it's safer vs. the many return pathways. + if unreserve { + defer func() { + var ( + _, hasPending = pool.pending[addr] + _, hasQueued = pool.queue[addr] + ) + if !hasPending && !hasQueued { + pool.reserve(addr, false) + } + }() + } + // Remove it from the list of known transactions + pool.all.Remove(hash) + if outofbound { + pool.priced.Removed(1) + } + if pool.locals.contains(addr) { + localGauge.Dec(1) + } + // Remove the transaction from the pending lists and reset the account nonce + if pending := pool.pending[addr]; pending != nil { + if removed, invalids := pending.Remove(tx); removed { + // If no more pending transactions are left, remove the list + if pending.Empty() { + delete(pool.pending, addr) + } + // Postpone any invalidated transactions + for _, tx := range invalids { + // Internal shuffle shouldn't touch the lookup set. + pool.enqueueTx(tx.Hash(), tx, false, false) + } + // Update the account nonce if needed + pool.pendingNonces.setIfLower(addr, tx.Nonce()) + // Reduce the pending counter + pendingGauge.Dec(int64(1 + len(invalids))) + return 1 + len(invalids) + } + } + // Transaction is in the future queue + if future := pool.queue[addr]; future != nil { + if removed, _ := future.Remove(tx); removed { + // Reduce the queued counter + queuedGauge.Dec(1) + } + if future.Empty() { + delete(pool.queue, addr) + delete(pool.beats, addr) + } + } + return 0 +} + +// requestReset requests a pool reset to the new head block. +// The returned channel is closed when the reset has occurred. +func (pool *LegacyPool) requestReset(oldHead *types.Header, newHead *types.Header) chan struct{} { + select { + case pool.reqResetCh <- &txpoolResetRequest{oldHead, newHead}: + return <-pool.reorgDoneCh + case <-pool.reorgShutdownCh: + return pool.reorgShutdownCh + } +} + +// requestPromoteExecutables requests transaction promotion checks for the given addresses. +// The returned channel is closed when the promotion checks have occurred. +func (pool *LegacyPool) requestPromoteExecutables(set *accountSet) chan struct{} { + select { + case pool.reqPromoteCh <- set: + return <-pool.reorgDoneCh + case <-pool.reorgShutdownCh: + return pool.reorgShutdownCh + } +} + +// queueTxEvent enqueues a transaction event to be sent in the next reorg run. +func (pool *LegacyPool) queueTxEvent(tx *types.Transaction) { + select { + case pool.queueTxEventCh <- tx: + case <-pool.reorgShutdownCh: + } +} + +// scheduleReorgLoop schedules runs of reset and promoteExecutables. Code above should not +// call those methods directly, but request them being run using requestReset and +// requestPromoteExecutables instead. +func (pool *LegacyPool) scheduleReorgLoop() { + defer pool.wg.Done() + + var ( + curDone chan struct{} // non-nil while runReorg is active + nextDone = make(chan struct{}) + launchNextRun bool + reset *txpoolResetRequest + dirtyAccounts *accountSet + queuedEvents = make(map[common.Address]*sortedMap) + ) + for { + // Launch next background reorg if needed + if curDone == nil && launchNextRun { + // Run the background reorg and announcements + go pool.runReorg(nextDone, reset, dirtyAccounts, queuedEvents) + + // Prepare everything for the next round of reorg + curDone, nextDone = nextDone, make(chan struct{}) + launchNextRun = false + + reset, dirtyAccounts = nil, nil + queuedEvents = make(map[common.Address]*sortedMap) + } + + select { + case req := <-pool.reqResetCh: + // Reset request: update head if request is already pending. + if reset == nil { + reset = req + } else { + reset.newHead = req.newHead + } + launchNextRun = true + pool.reorgDoneCh <- nextDone + + case req := <-pool.reqPromoteCh: + // Promote request: update address set if request is already pending. + if dirtyAccounts == nil { + dirtyAccounts = req + } else { + dirtyAccounts.merge(req) + } + launchNextRun = true + pool.reorgDoneCh <- nextDone + + case tx := <-pool.queueTxEventCh: + // Queue up the event, but don't schedule a reorg. It's up to the caller to + // request one later if they want the events sent. + addr, _ := types.Sender(pool.signer, tx) + if _, ok := queuedEvents[addr]; !ok { + queuedEvents[addr] = newSortedMap() + } + queuedEvents[addr].Put(tx) + + case <-curDone: + curDone = nil + + case <-pool.reorgShutdownCh: + // Wait for current run to finish. + if curDone != nil { + <-curDone + } + close(nextDone) + return + } + } +} + +// runReorg runs reset and promoteExecutables on behalf of scheduleReorgLoop. +func (pool *LegacyPool) runReorg(done chan struct{}, reset *txpoolResetRequest, dirtyAccounts *accountSet, events map[common.Address]*sortedMap) { + defer func(t0 time.Time) { + reorgDurationTimer.Update(time.Since(t0)) + }(time.Now()) + defer close(done) + + var promoteAddrs []common.Address + if dirtyAccounts != nil && reset == nil { + // Only dirty accounts need to be promoted, unless we're resetting. + // For resets, all addresses in the tx queue will be promoted and + // the flatten operation can be avoided. + promoteAddrs = dirtyAccounts.flatten() + } + pool.mu.Lock() + if reset != nil { + // Reset from the old head to the new, rescheduling any reorged transactions + pool.reset(reset.oldHead, reset.newHead) + + // Nonces were reset, discard any events that became stale + for addr := range events { + events[addr].Forward(pool.pendingNonces.get(addr)) + if events[addr].Len() == 0 { + delete(events, addr) + } + } + // Reset needs promote for all addresses + promoteAddrs = make([]common.Address, 0, len(pool.queue)) + for addr := range pool.queue { + promoteAddrs = append(promoteAddrs, addr) + } + } + // Check for pending transactions for every account that sent new ones + promoted := pool.promoteExecutables(promoteAddrs) + + // If a new block appeared, validate the pool of pending transactions. This will + // remove any transaction that has been included in the block or was invalidated + // because of another transaction (e.g. higher gas price). + if reset != nil { + pool.demoteUnexecutables() + if reset.newHead != nil { + if pool.chainconfig.IsLondon(new(big.Int).Add(reset.newHead.Number, big.NewInt(1))) { + pendingBaseFee := eip1559.CalcBaseFee(pool.chainconfig, reset.newHead) + pool.priced.SetBaseFee(pendingBaseFee) + } else { + pool.priced.Reheap() + } + } + // Update all accounts to the latest known pending nonce + nonces := make(map[common.Address]uint64, len(pool.pending)) + for addr, list := range pool.pending { + highestPending := list.LastElement() + nonces[addr] = highestPending.Nonce() + 1 + } + pool.pendingNonces.setAll(nonces) + } + // Ensure pool.queue and pool.pending sizes stay within the configured limits. + pool.truncatePending() + pool.truncateQueue() + + dropBetweenReorgHistogram.Update(int64(pool.changesSinceReorg)) + pool.changesSinceReorg = 0 // Reset change counter + pool.mu.Unlock() + + // Notify subsystems for newly added transactions + for _, tx := range promoted { + addr, _ := types.Sender(pool.signer, tx) + if _, ok := events[addr]; !ok { + events[addr] = newSortedMap() + } + events[addr].Put(tx) + } + if len(events) > 0 { + var txs []*types.Transaction + for _, set := range events { + txs = append(txs, set.Flatten()...) + } + pool.txFeed.Send(core.NewTxsEvent{Txs: txs}) + } +} + +// reset retrieves the current state of the blockchain and ensures the content +// of the transaction pool is valid with regard to the chain state. +func (pool *LegacyPool) reset(oldHead, newHead *types.Header) { + // If we're reorging an old state, reinject all dropped transactions + var reinject types.Transactions + + if oldHead != nil && oldHead.Hash() != newHead.ParentHash { + // If the reorg is too deep, avoid doing it (will happen during fast sync) + oldNum := oldHead.Number.Uint64() + newNum := newHead.Number.Uint64() + + if depth := uint64(math.Abs(float64(oldNum) - float64(newNum))); depth > 64 { + log.Debug("Skipping deep transaction reorg", "depth", depth) + } else { + // Reorg seems shallow enough to pull in all transactions into memory + var ( + rem = pool.chain.GetBlock(oldHead.Hash(), oldHead.Number.Uint64()) + add = pool.chain.GetBlock(newHead.Hash(), newHead.Number.Uint64()) + ) + if rem == nil { + // This can happen if a setHead is performed, where we simply discard the old + // head from the chain. + // If that is the case, we don't have the lost transactions anymore, and + // there's nothing to add + if newNum >= oldNum { + // If we reorged to a same or higher number, then it's not a case of setHead + log.Warn("Transaction pool reset with missing old head", + "old", oldHead.Hash(), "oldnum", oldNum, "new", newHead.Hash(), "newnum", newNum) + return + } + // If the reorg ended up on a lower number, it's indicative of setHead being the cause + log.Debug("Skipping transaction reset caused by setHead", + "old", oldHead.Hash(), "oldnum", oldNum, "new", newHead.Hash(), "newnum", newNum) + // We still need to update the current state s.th. the lost transactions can be readded by the user + } else { + if add == nil { + // if the new head is nil, it means that something happened between + // the firing of newhead-event and _now_: most likely a + // reorg caused by sync-reversion or explicit sethead back to an + // earlier block. + log.Warn("Transaction pool reset with missing new head", "number", newHead.Number, "hash", newHead.Hash()) + return + } + var discarded, included types.Transactions + for rem.NumberU64() > add.NumberU64() { + discarded = append(discarded, rem.Transactions()...) + if rem = pool.chain.GetBlock(rem.ParentHash(), rem.NumberU64()-1); rem == nil { + log.Error("Unrooted old chain seen by tx pool", "block", oldHead.Number, "hash", oldHead.Hash()) + return + } + } + for add.NumberU64() > rem.NumberU64() { + included = append(included, add.Transactions()...) + if add = pool.chain.GetBlock(add.ParentHash(), add.NumberU64()-1); add == nil { + log.Error("Unrooted new chain seen by tx pool", "block", newHead.Number, "hash", newHead.Hash()) + return + } + } + for rem.Hash() != add.Hash() { + discarded = append(discarded, rem.Transactions()...) + if rem = pool.chain.GetBlock(rem.ParentHash(), rem.NumberU64()-1); rem == nil { + log.Error("Unrooted old chain seen by tx pool", "block", oldHead.Number, "hash", oldHead.Hash()) + return + } + included = append(included, add.Transactions()...) + if add = pool.chain.GetBlock(add.ParentHash(), add.NumberU64()-1); add == nil { + log.Error("Unrooted new chain seen by tx pool", "block", newHead.Number, "hash", newHead.Hash()) + return + } + } + lost := make([]*types.Transaction, 0, len(discarded)) + for _, tx := range types.TxDifference(discarded, included) { + if pool.Filter(tx) { + lost = append(lost, tx) + } + } + reinject = lost + } + } + } + // Initialize the internal state to the current head + if newHead == nil { + newHead = pool.chain.CurrentBlock() // Special case during testing + } + statedb, err := pool.chain.StateAt(newHead.Root) + if err != nil { + log.Error("Failed to reset txpool state", "err", err) + return + } + pool.currentHead.Store(newHead) + pool.currentState = statedb + pool.pendingNonces = newNoncer(statedb) + + // Inject any transactions discarded due to reorgs + log.Debug("Reinjecting stale transactions", "count", len(reinject)) + core.SenderCacher.Recover(pool.signer, reinject) + pool.addTxsLocked(reinject, false) +} + +// promoteExecutables moves transactions that have become processable from the +// future queue to the set of pending transactions. During this process, all +// invalidated transactions (low nonce, low balance) are deleted. +func (pool *LegacyPool) promoteExecutables(accounts []common.Address) []*types.Transaction { + // Track the promoted transactions to broadcast them at once + var promoted []*types.Transaction + + // Iterate over all accounts and promote any executable transactions + gasLimit := pool.currentHead.Load().GasLimit + for _, addr := range accounts { + list := pool.queue[addr] + if list == nil { + continue // Just in case someone calls with a non existing account + } + // Drop all transactions that are deemed too old (low nonce) + forwards := list.Forward(pool.currentState.GetNonce(addr)) + for _, tx := range forwards { + hash := tx.Hash() + pool.all.Remove(hash) + } + log.Trace("Removed old queued transactions", "count", len(forwards)) + // Drop all transactions that are too costly (low balance or out of gas) + drops, _ := list.Filter(pool.currentState.GetBalance(addr), gasLimit) + for _, tx := range drops { + hash := tx.Hash() + pool.all.Remove(hash) + } + log.Trace("Removed unpayable queued transactions", "count", len(drops)) + queuedNofundsMeter.Mark(int64(len(drops))) + + // Gather all executable transactions and promote them + readies := list.Ready(pool.pendingNonces.get(addr)) + for _, tx := range readies { + hash := tx.Hash() + if pool.promoteTx(addr, hash, tx) { + promoted = append(promoted, tx) + } + } + log.Trace("Promoted queued transactions", "count", len(promoted)) + queuedGauge.Dec(int64(len(readies))) + + // Drop all transactions over the allowed limit + var caps types.Transactions + if !pool.locals.contains(addr) { + caps = list.Cap(int(pool.config.AccountQueue)) + for _, tx := range caps { + hash := tx.Hash() + pool.all.Remove(hash) + log.Trace("Removed cap-exceeding queued transaction", "hash", hash) + } + queuedRateLimitMeter.Mark(int64(len(caps))) + } + // Mark all the items dropped as removed + pool.priced.Removed(len(forwards) + len(drops) + len(caps)) + queuedGauge.Dec(int64(len(forwards) + len(drops) + len(caps))) + if pool.locals.contains(addr) { + localGauge.Dec(int64(len(forwards) + len(drops) + len(caps))) + } + // Delete the entire queue entry if it became empty. + if list.Empty() { + delete(pool.queue, addr) + delete(pool.beats, addr) + if _, ok := pool.pending[addr]; !ok { + pool.reserve(addr, false) + } + } + } + return promoted +} + +// truncatePending removes transactions from the pending queue if the pool is above the +// pending limit. The algorithm tries to reduce transaction counts by an approximately +// equal number for all for accounts with many pending transactions. +func (pool *LegacyPool) truncatePending() { + pending := uint64(0) + for _, list := range pool.pending { + pending += uint64(list.Len()) + } + if pending <= pool.config.GlobalSlots { + return + } + + pendingBeforeCap := pending + // Assemble a spam order to penalize large transactors first + spammers := prque.New[int64, common.Address](nil) + for addr, list := range pool.pending { + // Only evict transactions from high rollers + if !pool.locals.contains(addr) && uint64(list.Len()) > pool.config.AccountSlots { + spammers.Push(addr, int64(list.Len())) + } + } + // Gradually drop transactions from offenders + offenders := []common.Address{} + for pending > pool.config.GlobalSlots && !spammers.Empty() { + // Retrieve the next offender if not local address + offender, _ := spammers.Pop() + offenders = append(offenders, offender) + + // Equalize balances until all the same or below threshold + if len(offenders) > 1 { + // Calculate the equalization threshold for all current offenders + threshold := pool.pending[offender].Len() + + // Iteratively reduce all offenders until below limit or threshold reached + for pending > pool.config.GlobalSlots && pool.pending[offenders[len(offenders)-2]].Len() > threshold { + for i := 0; i < len(offenders)-1; i++ { + list := pool.pending[offenders[i]] + + caps := list.Cap(list.Len() - 1) + for _, tx := range caps { + // Drop the transaction from the global pools too + hash := tx.Hash() + pool.all.Remove(hash) + + // Update the account nonce to the dropped transaction + pool.pendingNonces.setIfLower(offenders[i], tx.Nonce()) + log.Trace("Removed fairness-exceeding pending transaction", "hash", hash) + } + pool.priced.Removed(len(caps)) + pendingGauge.Dec(int64(len(caps))) + if pool.locals.contains(offenders[i]) { + localGauge.Dec(int64(len(caps))) + } + pending-- + } + } + } + } + + // If still above threshold, reduce to limit or min allowance + if pending > pool.config.GlobalSlots && len(offenders) > 0 { + for pending > pool.config.GlobalSlots && uint64(pool.pending[offenders[len(offenders)-1]].Len()) > pool.config.AccountSlots { + for _, addr := range offenders { + list := pool.pending[addr] + + caps := list.Cap(list.Len() - 1) + for _, tx := range caps { + // Drop the transaction from the global pools too + hash := tx.Hash() + pool.all.Remove(hash) + + // Update the account nonce to the dropped transaction + pool.pendingNonces.setIfLower(addr, tx.Nonce()) + log.Trace("Removed fairness-exceeding pending transaction", "hash", hash) + } + pool.priced.Removed(len(caps)) + pendingGauge.Dec(int64(len(caps))) + if pool.locals.contains(addr) { + localGauge.Dec(int64(len(caps))) + } + pending-- + } + } + } + pendingRateLimitMeter.Mark(int64(pendingBeforeCap - pending)) +} + +// truncateQueue drops the oldest transactions in the queue if the pool is above the global queue limit. +func (pool *LegacyPool) truncateQueue() { + queued := uint64(0) + for _, list := range pool.queue { + queued += uint64(list.Len()) + } + if queued <= pool.config.GlobalQueue { + return + } + + // Sort all accounts with queued transactions by heartbeat + addresses := make(addressesByHeartbeat, 0, len(pool.queue)) + for addr := range pool.queue { + if !pool.locals.contains(addr) { // don't drop locals + addresses = append(addresses, addressByHeartbeat{addr, pool.beats[addr]}) + } + } + sort.Sort(sort.Reverse(addresses)) + + // Drop transactions until the total is below the limit or only locals remain + for drop := queued - pool.config.GlobalQueue; drop > 0 && len(addresses) > 0; { + addr := addresses[len(addresses)-1] + list := pool.queue[addr.address] + + addresses = addresses[:len(addresses)-1] + + // Drop all transactions if they are less than the overflow + if size := uint64(list.Len()); size <= drop { + for _, tx := range list.Flatten() { + pool.removeTx(tx.Hash(), true, true) + } + drop -= size + queuedRateLimitMeter.Mark(int64(size)) + continue + } + // Otherwise drop only last few transactions + txs := list.Flatten() + for i := len(txs) - 1; i >= 0 && drop > 0; i-- { + pool.removeTx(txs[i].Hash(), true, true) + drop-- + queuedRateLimitMeter.Mark(1) + } + } +} + +// demoteUnexecutables removes invalid and processed transactions from the pools +// executable/pending queue and any subsequent transactions that become unexecutable +// are moved back into the future queue. +// +// Note: transactions are not marked as removed in the priced list because re-heaping +// is always explicitly triggered by SetBaseFee and it would be unnecessary and wasteful +// to trigger a re-heap is this function +func (pool *LegacyPool) demoteUnexecutables() { + // Iterate over all accounts and demote any non-executable transactions + gasLimit := pool.currentHead.Load().GasLimit + for addr, list := range pool.pending { + nonce := pool.currentState.GetNonce(addr) + + // Drop all transactions that are deemed too old (low nonce) + olds := list.Forward(nonce) + for _, tx := range olds { + hash := tx.Hash() + pool.all.Remove(hash) + log.Trace("Removed old pending transaction", "hash", hash) + } + // Drop all transactions that are too costly (low balance or out of gas), and queue any invalids back for later + drops, invalids := list.Filter(pool.currentState.GetBalance(addr), gasLimit) + for _, tx := range drops { + hash := tx.Hash() + log.Trace("Removed unpayable pending transaction", "hash", hash) + pool.all.Remove(hash) + } + pendingNofundsMeter.Mark(int64(len(drops))) + + for _, tx := range invalids { + hash := tx.Hash() + log.Trace("Demoting pending transaction", "hash", hash) + + // Internal shuffle shouldn't touch the lookup set. + pool.enqueueTx(hash, tx, false, false) + } + pendingGauge.Dec(int64(len(olds) + len(drops) + len(invalids))) + if pool.locals.contains(addr) { + localGauge.Dec(int64(len(olds) + len(drops) + len(invalids))) + } + // If there's a gap in front, alert (should never happen) and postpone all transactions + if list.Len() > 0 && list.txs.Get(nonce) == nil { + gapped := list.Cap(0) + for _, tx := range gapped { + hash := tx.Hash() + log.Error("Demoting invalidated transaction", "hash", hash) + + // Internal shuffle shouldn't touch the lookup set. + pool.enqueueTx(hash, tx, false, false) + } + pendingGauge.Dec(int64(len(gapped))) + } + // Delete the entire pending entry if it became empty. + if list.Empty() { + delete(pool.pending, addr) + if _, ok := pool.queue[addr]; !ok { + pool.reserve(addr, false) + } + } + } +} + +// addressByHeartbeat is an account address tagged with its last activity timestamp. +type addressByHeartbeat struct { + address common.Address + heartbeat time.Time +} + +type addressesByHeartbeat []addressByHeartbeat + +func (a addressesByHeartbeat) Len() int { return len(a) } +func (a addressesByHeartbeat) Less(i, j int) bool { return a[i].heartbeat.Before(a[j].heartbeat) } +func (a addressesByHeartbeat) Swap(i, j int) { a[i], a[j] = a[j], a[i] } + +// accountSet is simply a set of addresses to check for existence, and a signer +// capable of deriving addresses from transactions. +type accountSet struct { + accounts map[common.Address]struct{} + signer types.Signer + cache *[]common.Address +} + +// newAccountSet creates a new address set with an associated signer for sender +// derivations. +func newAccountSet(signer types.Signer, addrs ...common.Address) *accountSet { + as := &accountSet{ + accounts: make(map[common.Address]struct{}, len(addrs)), + signer: signer, + } + for _, addr := range addrs { + as.add(addr) + } + return as +} + +// contains checks if a given address is contained within the set. +func (as *accountSet) contains(addr common.Address) bool { + _, exist := as.accounts[addr] + return exist +} + +// containsTx checks if the sender of a given tx is within the set. If the sender +// cannot be derived, this method returns false. +func (as *accountSet) containsTx(tx *types.Transaction) bool { + if addr, err := types.Sender(as.signer, tx); err == nil { + return as.contains(addr) + } + return false +} + +// add inserts a new address into the set to track. +func (as *accountSet) add(addr common.Address) { + as.accounts[addr] = struct{}{} + as.cache = nil +} + +// addTx adds the sender of tx into the set. +func (as *accountSet) addTx(tx *types.Transaction) { + if addr, err := types.Sender(as.signer, tx); err == nil { + as.add(addr) + } +} + +// flatten returns the list of addresses within this set, also caching it for later +// 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 + } + 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{}{} + } + as.cache = nil +} + +// lookup is used internally by LegacyPool to track transactions while allowing +// lookup without mutex contention. +// +// Note, although this type is properly protected against concurrent access, it +// is **not** a type that should ever be mutated or even exposed outside of the +// transaction pool, since its internal state is tightly coupled with the pools +// internal mechanisms. The sole purpose of the type is to permit out-of-bound +// peeking into the pool in LegacyPool.Get without having to acquire the widely scoped +// LegacyPool.mu mutex. +// +// This lookup set combines the notion of "local transactions", which is useful +// to build upper-level structure. +type lookup struct { + slots int + lock sync.RWMutex + locals map[common.Hash]*types.Transaction + remotes map[common.Hash]*types.Transaction +} + +// newLookup returns a new lookup structure. +func newLookup() *lookup { + return &lookup{ + locals: make(map[common.Hash]*types.Transaction), + remotes: make(map[common.Hash]*types.Transaction), + } +} + +// Range calls f on each key and value present in the map. The callback passed +// should return the indicator whether the iteration needs to be continued. +// Callers need to specify which set (or both) to be iterated. +func (t *lookup) Range(f func(hash common.Hash, tx *types.Transaction, local bool) bool, local bool, remote bool) { + t.lock.RLock() + defer t.lock.RUnlock() + + if local { + for key, value := range t.locals { + if !f(key, value, true) { + return + } + } + } + if remote { + for key, value := range t.remotes { + if !f(key, value, false) { + return + } + } + } +} + +// Get returns a transaction if it exists in the lookup, or nil if not found. +func (t *lookup) Get(hash common.Hash) *types.Transaction { + t.lock.RLock() + defer t.lock.RUnlock() + + if tx := t.locals[hash]; tx != nil { + return tx + } + return t.remotes[hash] +} + +// GetLocal returns a transaction if it exists in the lookup, or nil if not found. +func (t *lookup) GetLocal(hash common.Hash) *types.Transaction { + t.lock.RLock() + defer t.lock.RUnlock() + + return t.locals[hash] +} + +// GetRemote returns a transaction if it exists in the lookup, or nil if not found. +func (t *lookup) GetRemote(hash common.Hash) *types.Transaction { + t.lock.RLock() + defer t.lock.RUnlock() + + return t.remotes[hash] +} + +// Count returns the current number of transactions in the lookup. +func (t *lookup) Count() int { + t.lock.RLock() + defer t.lock.RUnlock() + + return len(t.locals) + len(t.remotes) +} + +// LocalCount returns the current number of local transactions in the lookup. +func (t *lookup) LocalCount() int { + t.lock.RLock() + defer t.lock.RUnlock() + + return len(t.locals) +} + +// RemoteCount returns the current number of remote transactions in the lookup. +func (t *lookup) RemoteCount() int { + t.lock.RLock() + defer t.lock.RUnlock() + + return len(t.remotes) +} + +// Slots returns the current number of slots used in the lookup. +func (t *lookup) Slots() int { + t.lock.RLock() + defer t.lock.RUnlock() + + return t.slots +} + +// Add adds a transaction to the lookup. +func (t *lookup) Add(tx *types.Transaction, local bool) { + t.lock.Lock() + defer t.lock.Unlock() + + t.slots += numSlots(tx) + slotsGauge.Update(int64(t.slots)) + + if local { + t.locals[tx.Hash()] = tx + } else { + t.remotes[tx.Hash()] = tx + } +} + +// Remove removes a transaction from the lookup. +func (t *lookup) Remove(hash common.Hash) { + t.lock.Lock() + defer t.lock.Unlock() + + tx, ok := t.locals[hash] + if !ok { + tx, ok = t.remotes[hash] + } + if !ok { + log.Error("No transaction found to be deleted", "hash", hash) + return + } + t.slots -= numSlots(tx) + slotsGauge.Update(int64(t.slots)) + + delete(t.locals, hash) + delete(t.remotes, hash) +} + +// RemoteToLocals migrates the transactions belongs to the given locals to locals +// set. The assumption is held the locals set is thread-safe to be used. +func (t *lookup) RemoteToLocals(locals *accountSet) int { + t.lock.Lock() + defer t.lock.Unlock() + + var migrated int + for hash, tx := range t.remotes { + if locals.containsTx(tx) { + t.locals[hash] = tx + delete(t.remotes, hash) + migrated += 1 + } + } + return migrated +} + +// RemotesBelowTip finds all remote transactions below the given tip threshold. +func (t *lookup) RemotesBelowTip(threshold *big.Int) types.Transactions { + found := make(types.Transactions, 0, 128) + t.Range(func(hash common.Hash, tx *types.Transaction, local bool) bool { + if tx.GasTipCapIntCmp(threshold) < 0 { + found = append(found, tx) + } + return true + }, false, true) // Only iterate remotes + return found +} + +// numSlots calculates the number of slots needed for a single transaction. +func numSlots(tx *types.Transaction) int { + return int((tx.Size() + txSlotSize - 1) / txSlotSize) +} diff --git a/core/txpool/txpool2_test.go b/core/txpool/legacypool/legacypool2_test.go similarity index 84% rename from core/txpool/txpool2_test.go rename to core/txpool/legacypool/legacypool2_test.go index d7ae3bdb1b..a73c1bb8a7 100644 --- a/core/txpool/txpool2_test.go +++ b/core/txpool/legacypool/legacypool2_test.go @@ -13,7 +13,7 @@ // // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package txpool +package legacypool import ( "crypto/ecdsa" @@ -33,7 +33,7 @@ func pricedValuedTransaction(nonce uint64, value int64, gaslimit uint64, gaspric return tx } -func count(t *testing.T, pool *TxPool) (pending int, queued int) { +func count(t *testing.T, pool *LegacyPool) (pending int, queued int) { t.Helper() pending, queued = pool.stats() if err := validatePoolInternals(pool); err != nil { @@ -42,7 +42,7 @@ func count(t *testing.T, pool *TxPool) (pending int, queued int) { return pending, queued } -func fillPool(t testing.TB, pool *TxPool) { +func fillPool(t testing.TB, pool *LegacyPool) { t.Helper() // Create a number of test accounts, fund them and make transactions executableTxs := types.Transactions{} @@ -56,8 +56,8 @@ func fillPool(t testing.TB, pool *TxPool) { } } // Import the batch and verify that limits have been enforced - pool.AddRemotesSync(executableTxs) - pool.AddRemotesSync(nonExecutableTxs) + pool.addRemotesSync(executableTxs) + pool.addRemotesSync(nonExecutableTxs) pending, queued := pool.Stats() slots := pool.all.Slots() // sanity-check that the test prerequisites are ok (pending full) @@ -79,12 +79,13 @@ func TestTransactionFutureAttack(t *testing.T) { // Create the pool to test the limit enforcement with statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) + blockchain := newTestBlockChain(eip1559Config, 1000000, statedb, new(event.Feed)) config := testTxPoolConfig config.GlobalQueue = 100 config.GlobalSlots = 100 - pool := NewTxPool(config, eip1559Config, blockchain) - defer pool.Stop() + pool := New(config, blockchain) + pool.Init(new(big.Int).SetUint64(config.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver()) + defer pool.Close() fillPool(t, pool) pending, _ := pool.Stats() // Now, future transaction attack starts, let's add a bunch of expensive non-executables, and see if the pending-count drops @@ -96,7 +97,7 @@ func TestTransactionFutureAttack(t *testing.T) { futureTxs = append(futureTxs, pricedTransaction(1000+uint64(j), 100000, big.NewInt(500), key)) } for i := 0; i < 5; i++ { - pool.AddRemotesSync(futureTxs) + pool.addRemotesSync(futureTxs) newPending, newQueued := count(t, pool) t.Logf("pending: %d queued: %d, all: %d\n", newPending, newQueued, pool.all.Slots()) } @@ -115,9 +116,10 @@ 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) - blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) - pool := NewTxPool(testTxPoolConfig, eip1559Config, blockchain) - defer pool.Stop() + blockchain := newTestBlockChain(eip1559Config, 1000000, statedb, new(event.Feed)) + pool := New(testTxPoolConfig, blockchain) + pool.Init(new(big.Int).SetUint64(testTxPoolConfig.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver()) + defer pool.Close() // Create a number of test accounts, fund them and make transactions fillPool(t, pool) @@ -131,7 +133,7 @@ func TestTransactionFuture1559(t *testing.T) { 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)) } - pool.AddRemotesSync(futureTxs) + pool.addRemotesSync(futureTxs) } newPending, _ := pool.Stats() // Pending should not have been touched @@ -147,9 +149,10 @@ 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) - blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) - pool := NewTxPool(testTxPoolConfig, eip1559Config, blockchain) - defer pool.Stop() + blockchain := newTestBlockChain(eip1559Config, 1000000, statedb, new(event.Feed)) + pool := New(testTxPoolConfig, blockchain) + pool.Init(new(big.Int).SetUint64(testTxPoolConfig.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver()) + defer pool.Close() // Create a number of test accounts, fund them and make transactions fillPool(t, pool) @@ -181,7 +184,7 @@ func TestTransactionZAttack(t *testing.T) { key, _ := crypto.GenerateKey() pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000)) futureTxs = append(futureTxs, pricedTransaction(1000+uint64(j), 21000, big.NewInt(500), key)) - pool.AddRemotesSync(futureTxs) + pool.addRemotesSync(futureTxs) } overDraftTxs := types.Transactions{} @@ -192,11 +195,11 @@ func TestTransactionZAttack(t *testing.T) { overDraftTxs = append(overDraftTxs, pricedValuedTransaction(uint64(j), 600000000000, 21000, big.NewInt(500), key)) } } - pool.AddRemotesSync(overDraftTxs) - pool.AddRemotesSync(overDraftTxs) - pool.AddRemotesSync(overDraftTxs) - pool.AddRemotesSync(overDraftTxs) - pool.AddRemotesSync(overDraftTxs) + pool.addRemotesSync(overDraftTxs) + pool.addRemotesSync(overDraftTxs) + pool.addRemotesSync(overDraftTxs) + pool.addRemotesSync(overDraftTxs) + pool.addRemotesSync(overDraftTxs) newPending, newQueued := count(t, pool) newIvPending := countInvalidPending() @@ -214,12 +217,13 @@ 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) - blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) + blockchain := newTestBlockChain(eip1559Config, 1000000, statedb, new(event.Feed)) config := testTxPoolConfig config.GlobalQueue = 100 config.GlobalSlots = 100 - pool := NewTxPool(config, eip1559Config, blockchain) - defer pool.Stop() + pool := New(config, blockchain) + pool.Init(new(big.Int).SetUint64(testTxPoolConfig.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver()) + defer pool.Close() fillPool(b, pool) key, _ := crypto.GenerateKey() @@ -231,6 +235,6 @@ func BenchmarkFutureAttack(b *testing.B) { } b.ResetTimer() for i := 0; i < 5; i++ { - pool.AddRemotesSync(futureTxs) + pool.addRemotesSync(futureTxs) } } diff --git a/core/txpool/txpool_test.go b/core/txpool/legacypool/legacypool_test.go similarity index 85% rename from core/txpool/txpool_test.go rename to core/txpool/legacypool/legacypool_test.go index 22e106aaf8..a8f3dd7d86 100644 --- a/core/txpool/txpool_test.go +++ b/core/txpool/legacypool/legacypool_test.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 txpool +package legacypool import ( "crypto/ecdsa" @@ -24,6 +24,7 @@ import ( "math/big" "math/rand" "os" + "sync" "sync/atomic" "testing" "time" @@ -32,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/txpool" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/event" @@ -59,17 +61,22 @@ func init() { } type testBlockChain struct { + config *params.ChainConfig gasLimit atomic.Uint64 statedb *state.StateDB chainHeadFeed *event.Feed } -func newTestBlockChain(gasLimit uint64, statedb *state.StateDB, chainHeadFeed *event.Feed) *testBlockChain { - bc := testBlockChain{statedb: statedb, chainHeadFeed: new(event.Feed)} +func newTestBlockChain(config *params.ChainConfig, gasLimit uint64, statedb *state.StateDB, chainHeadFeed *event.Feed) *testBlockChain { + bc := testBlockChain{config: config, statedb: statedb, chainHeadFeed: new(event.Feed)} bc.gasLimit.Store(gasLimit) return &bc } +func (bc *testBlockChain) Config() *params.ChainConfig { + return bc.config +} + func (bc *testBlockChain) CurrentBlock() *types.Header { return &types.Header{ Number: new(big.Int), @@ -121,24 +128,51 @@ func dynamicFeeTx(nonce uint64, gaslimit uint64, gasFee *big.Int, tip *big.Int, return tx } -func setupPool() (*TxPool, *ecdsa.PrivateKey) { +func makeAddressReserver() txpool.AddressReserver { + var ( + reserved = make(map[common.Address]struct{}) + lock sync.Mutex + ) + return func(addr common.Address, reserve bool) error { + lock.Lock() + defer lock.Unlock() + + _, exists := reserved[addr] + if reserve { + if exists { + panic("already reserved") + } + reserved[addr] = struct{}{} + return nil + } + if !exists { + panic("not reserved") + } + delete(reserved, addr) + return nil + } +} + +func setupPool() (*LegacyPool, *ecdsa.PrivateKey) { return setupPoolWithConfig(params.TestChainConfig) } -func setupPoolWithConfig(config *params.ChainConfig) (*TxPool, *ecdsa.PrivateKey) { +func setupPoolWithConfig(config *params.ChainConfig) (*LegacyPool, *ecdsa.PrivateKey) { statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - blockchain := newTestBlockChain(10000000, statedb, new(event.Feed)) + blockchain := newTestBlockChain(config, 10000000, statedb, new(event.Feed)) key, _ := crypto.GenerateKey() - pool := NewTxPool(testTxPoolConfig, config, blockchain) - + pool := New(testTxPoolConfig, blockchain) + if err := pool.Init(new(big.Int).SetUint64(testTxPoolConfig.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver()); err != nil { + panic(err) + } // wait for the pool to initialize <-pool.initDoneCh return pool, key } // validatePoolInternals checks various consistency invariants within the pool. -func validatePoolInternals(pool *TxPool) error { +func validatePoolInternals(pool *LegacyPool) error { pool.mu.RLock() defer pool.mu.RUnlock() @@ -242,20 +276,21 @@ func TestStateChangeDuringReset(t *testing.T) { // setup pool with 2 transaction in it statedb.SetBalance(address, new(big.Int).SetUint64(params.Ether)) - blockchain := &testChain{newTestBlockChain(1000000000, statedb, new(event.Feed)), address, &trigger} + blockchain := &testChain{newTestBlockChain(params.TestChainConfig, 1000000000, statedb, new(event.Feed)), address, &trigger} tx0 := transaction(0, 100000, key) tx1 := transaction(1, 100000, key) - pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain) - defer pool.Stop() + pool := New(testTxPoolConfig, blockchain) + pool.Init(new(big.Int).SetUint64(testTxPoolConfig.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver()) + defer pool.Close() nonce := pool.Nonce(address) if nonce != 0 { t.Fatalf("Invalid nonce, want 0, got %d", nonce) } - pool.AddRemotesSync([]*types.Transaction{tx0, tx1}) + pool.addRemotesSync([]*types.Transaction{tx0, tx1}) nonce = pool.Nonce(address) if nonce != 2 { @@ -272,13 +307,13 @@ func TestStateChangeDuringReset(t *testing.T) { } } -func testAddBalance(pool *TxPool, addr common.Address, amount *big.Int) { +func testAddBalance(pool *LegacyPool, addr common.Address, amount *big.Int) { pool.mu.Lock() pool.currentState.AddBalance(addr, amount) pool.mu.Unlock() } -func testSetNonce(pool *TxPool, addr common.Address, nonce uint64) { +func testSetNonce(pool *LegacyPool, addr common.Address, nonce uint64) { pool.mu.Lock() pool.currentState.SetNonce(addr, nonce) pool.mu.Unlock() @@ -288,36 +323,36 @@ func TestInvalidTransactions(t *testing.T) { t.Parallel() pool, key := setupPool() - defer pool.Stop() + defer pool.Close() tx := transaction(0, 100, key) from, _ := deriveSender(tx) // Intrinsic gas too low testAddBalance(pool, from, big.NewInt(1)) - if err, want := pool.AddRemote(tx), core.ErrIntrinsicGas; !errors.Is(err, want) { + if err, want := pool.addRemote(tx), core.ErrIntrinsicGas; !errors.Is(err, want) { t.Errorf("want %v have %v", want, err) } // Insufficient funds tx = transaction(0, 100000, key) - if err, want := pool.AddRemote(tx), core.ErrInsufficientFunds; !errors.Is(err, want) { + if err, want := pool.addRemote(tx), core.ErrInsufficientFunds; !errors.Is(err, want) { t.Errorf("want %v have %v", want, err) } testSetNonce(pool, from, 1) testAddBalance(pool, from, big.NewInt(0xffffffffffffff)) tx = transaction(0, 100000, key) - if err, want := pool.AddRemote(tx), core.ErrNonceTooLow; !errors.Is(err, want) { + if err, want := pool.addRemote(tx), core.ErrNonceTooLow; !errors.Is(err, want) { t.Errorf("want %v have %v", want, err) } tx = transaction(1, 100000, key) - pool.gasPrice = big.NewInt(1000) - if err, want := pool.AddRemote(tx), ErrUnderpriced; !errors.Is(err, want) { + pool.gasTip.Store(big.NewInt(1000)) + if err, want := pool.addRemote(tx), txpool.ErrUnderpriced; !errors.Is(err, want) { t.Errorf("want %v have %v", want, err) } - if err := pool.AddLocal(tx); err != nil { + if err := pool.addLocal(tx); err != nil { t.Error("expected", nil, "got", err) } } @@ -326,7 +361,7 @@ func TestQueue(t *testing.T) { t.Parallel() pool, key := setupPool() - defer pool.Stop() + defer pool.Close() tx := transaction(0, 100, key) from, _ := deriveSender(tx) @@ -357,7 +392,7 @@ func TestQueue2(t *testing.T) { t.Parallel() pool, key := setupPool() - defer pool.Stop() + defer pool.Close() tx1 := transaction(0, 100, key) tx2 := transaction(10, 100, key) @@ -383,13 +418,13 @@ func TestNegativeValue(t *testing.T) { t.Parallel() pool, key := setupPool() - defer pool.Stop() + defer pool.Close() tx, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(-1), 100, big.NewInt(1), nil), types.HomesteadSigner{}, key) from, _ := deriveSender(tx) testAddBalance(pool, from, big.NewInt(1)) - if err := pool.AddRemote(tx); err != ErrNegativeValue { - t.Error("expected", ErrNegativeValue, "got", err) + if err := pool.addRemote(tx); err != txpool.ErrNegativeValue { + t.Error("expected", txpool.ErrNegativeValue, "got", err) } } @@ -397,11 +432,11 @@ func TestTipAboveFeeCap(t *testing.T) { t.Parallel() pool, key := setupPoolWithConfig(eip1559Config) - defer pool.Stop() + defer pool.Close() tx := dynamicFeeTx(0, 100, big.NewInt(1), big.NewInt(2), key) - if err := pool.AddRemote(tx); err != core.ErrTipAboveFeeCap { + if err := pool.addRemote(tx); err != core.ErrTipAboveFeeCap { t.Error("expected", core.ErrTipAboveFeeCap, "got", err) } } @@ -410,18 +445,18 @@ func TestVeryHighValues(t *testing.T) { t.Parallel() pool, key := setupPoolWithConfig(eip1559Config) - defer pool.Stop() + defer pool.Close() veryBigNumber := big.NewInt(1) veryBigNumber.Lsh(veryBigNumber, 300) tx := dynamicFeeTx(0, 100, big.NewInt(1), veryBigNumber, key) - if err := pool.AddRemote(tx); err != core.ErrTipVeryHigh { + if err := pool.addRemote(tx); err != core.ErrTipVeryHigh { t.Error("expected", core.ErrTipVeryHigh, "got", err) } tx2 := dynamicFeeTx(0, 100, veryBigNumber, big.NewInt(1), key) - if err := pool.AddRemote(tx2); err != core.ErrFeeCapVeryHigh { + if err := pool.addRemote(tx2); err != core.ErrFeeCapVeryHigh { t.Error("expected", core.ErrFeeCapVeryHigh, "got", err) } } @@ -430,14 +465,14 @@ func TestChainFork(t *testing.T) { t.Parallel() pool, key := setupPool() - defer pool.Stop() + defer pool.Close() addr := crypto.PubkeyToAddress(key.PublicKey) resetState := func() { statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) statedb.AddBalance(addr, big.NewInt(100000000000000)) - pool.chain = newTestBlockChain(1000000, statedb, new(event.Feed)) + pool.chain = newTestBlockChain(pool.chainconfig, 1000000, statedb, new(event.Feed)) <-pool.requestReset(nil, nil) } resetState() @@ -446,7 +481,7 @@ func TestChainFork(t *testing.T) { if _, err := pool.add(tx, false); err != nil { t.Error("didn't expect error", err) } - pool.removeTx(tx.Hash(), true) + pool.removeTx(tx.Hash(), true, true) // reset the pool's internal state resetState() @@ -459,14 +494,14 @@ func TestDoubleNonce(t *testing.T) { t.Parallel() pool, key := setupPool() - defer pool.Stop() + defer pool.Close() addr := crypto.PubkeyToAddress(key.PublicKey) resetState := func() { statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) statedb.AddBalance(addr, big.NewInt(100000000000000)) - pool.chain = newTestBlockChain(1000000, statedb, new(event.Feed)) + pool.chain = newTestBlockChain(pool.chainconfig, 1000000, statedb, new(event.Feed)) <-pool.requestReset(nil, nil) } resetState() @@ -510,7 +545,7 @@ func TestMissingNonce(t *testing.T) { t.Parallel() pool, key := setupPool() - defer pool.Stop() + defer pool.Close() addr := crypto.PubkeyToAddress(key.PublicKey) testAddBalance(pool, addr, big.NewInt(100000000000000)) @@ -534,7 +569,7 @@ func TestNonceRecovery(t *testing.T) { const n = 10 pool, key := setupPool() - defer pool.Stop() + defer pool.Close() addr := crypto.PubkeyToAddress(key.PublicKey) testSetNonce(pool, addr, n) @@ -542,7 +577,7 @@ func TestNonceRecovery(t *testing.T) { <-pool.requestReset(nil, nil) tx := transaction(n, 100000, key) - if err := pool.AddRemote(tx); err != nil { + if err := pool.addRemote(tx); err != nil { t.Error(err) } // simulate some weird re-order of transactions and missing nonce(s) @@ -560,7 +595,7 @@ func TestDropping(t *testing.T) { // Create a test account and fund it pool, key := setupPool() - defer pool.Stop() + defer pool.Close() account := crypto.PubkeyToAddress(key.PublicKey) testAddBalance(pool, account, big.NewInt(1000)) @@ -664,10 +699,11 @@ func TestPostponing(t *testing.T) { // Create the pool to test the postponing with statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) + blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) - pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain) - defer pool.Stop() + pool := New(testTxPoolConfig, blockchain) + pool.Init(new(big.Int).SetUint64(testTxPoolConfig.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver()) + defer pool.Close() // Create two test accounts to produce different gap profiles with keys := make([]*ecdsa.PrivateKey, 2) @@ -692,7 +728,7 @@ func TestPostponing(t *testing.T) { txs = append(txs, tx) } } - for i, err := range pool.AddRemotesSync(txs) { + for i, err := range pool.addRemotesSync(txs) { if err != nil { t.Fatalf("tx %d: failed to add transactions: %v", i, err) } @@ -777,7 +813,7 @@ func TestGapFilling(t *testing.T) { // Create a test account and fund it pool, key := setupPool() - defer pool.Stop() + defer pool.Close() account := crypto.PubkeyToAddress(key.PublicKey) testAddBalance(pool, account, big.NewInt(1000000)) @@ -788,7 +824,7 @@ func TestGapFilling(t *testing.T) { defer sub.Unsubscribe() // Create a pending and a queued transaction with a nonce-gap in between - pool.AddRemotesSync([]*types.Transaction{ + pool.addRemotesSync([]*types.Transaction{ transaction(0, 100000, key), transaction(2, 100000, key), }) @@ -831,7 +867,7 @@ func TestQueueAccountLimiting(t *testing.T) { // Create a test account and fund it pool, key := setupPool() - defer pool.Stop() + defer pool.Close() account := crypto.PubkeyToAddress(key.PublicKey) testAddBalance(pool, account, big.NewInt(1000000)) @@ -876,14 +912,15 @@ func testQueueGlobalLimiting(t *testing.T, nolocals bool) { // Create the pool to test the limit enforcement with statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) + blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) config := testTxPoolConfig config.NoLocals = nolocals config.GlobalQueue = config.AccountQueue*3 - 1 // reduce the queue limits to shorten test time (-1 to make it non divisible) - pool := NewTxPool(config, params.TestChainConfig, blockchain) - defer pool.Stop() + pool := New(config, blockchain) + pool.Init(new(big.Int).SetUint64(testTxPoolConfig.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver()) + defer pool.Close() // Create a number of test accounts and fund them (last one will be the local) keys := make([]*ecdsa.PrivateKey, 5) @@ -905,7 +942,7 @@ func testQueueGlobalLimiting(t *testing.T, nolocals bool) { nonces[addr]++ } // Import the batch and verify that limits have been enforced - pool.AddRemotesSync(txs) + pool.addRemotesSync(txs) queued := 0 for addr, list := range pool.queue { @@ -922,7 +959,7 @@ func testQueueGlobalLimiting(t *testing.T, nolocals bool) { for i := uint64(0); i < 3*config.GlobalQueue; i++ { txs = append(txs, transaction(i+1, 100000, local)) } - pool.AddLocals(txs) + pool.addLocals(txs) // If locals are disabled, the previous eviction algorithm should apply here too if nolocals { @@ -968,14 +1005,15 @@ func testQueueTimeLimiting(t *testing.T, nolocals bool) { // Create the pool to test the non-expiration enforcement statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) + blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) config := testTxPoolConfig config.Lifetime = time.Second config.NoLocals = nolocals - pool := NewTxPool(config, params.TestChainConfig, blockchain) - defer pool.Stop() + pool := New(config, blockchain) + pool.Init(new(big.Int).SetUint64(config.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver()) + defer pool.Close() // Create two test accounts to ensure remotes expire but locals do not local, _ := crypto.GenerateKey() @@ -985,10 +1023,10 @@ func testQueueTimeLimiting(t *testing.T, nolocals bool) { testAddBalance(pool, crypto.PubkeyToAddress(remote.PublicKey), big.NewInt(1000000000)) // Add the two transactions and ensure they both are queued up - if err := pool.AddLocal(pricedTransaction(1, 100000, big.NewInt(1), local)); err != nil { + if err := pool.addLocal(pricedTransaction(1, 100000, big.NewInt(1), local)); err != nil { t.Fatalf("failed to add local transaction: %v", err) } - if err := pool.AddRemote(pricedTransaction(1, 100000, big.NewInt(1), remote)); err != nil { + if err := pool.addRemote(pricedTransaction(1, 100000, big.NewInt(1), remote)); err != nil { t.Fatalf("failed to add remote transaction: %v", err) } pending, queued := pool.Stats() @@ -1055,7 +1093,7 @@ func testQueueTimeLimiting(t *testing.T, nolocals bool) { } // Queue gapped transactions - if err := pool.AddLocal(pricedTransaction(4, 100000, big.NewInt(1), local)); err != nil { + if err := pool.addLocal(pricedTransaction(4, 100000, big.NewInt(1), local)); err != nil { t.Fatalf("failed to add remote transaction: %v", err) } if err := pool.addRemoteSync(pricedTransaction(4, 100000, big.NewInt(1), remote)); err != nil { @@ -1064,7 +1102,7 @@ func testQueueTimeLimiting(t *testing.T, nolocals bool) { time.Sleep(5 * evictionInterval) // A half lifetime pass // Queue executable transactions, the life cycle should be restarted. - if err := pool.AddLocal(pricedTransaction(2, 100000, big.NewInt(1), local)); err != nil { + if err := pool.addLocal(pricedTransaction(2, 100000, big.NewInt(1), local)); err != nil { t.Fatalf("failed to add remote transaction: %v", err) } if err := pool.addRemoteSync(pricedTransaction(2, 100000, big.NewInt(1), remote)); err != nil { @@ -1078,7 +1116,7 @@ func testQueueTimeLimiting(t *testing.T, nolocals bool) { t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2) } if queued != 2 { - t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 3) + t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 2) } if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) @@ -1112,7 +1150,7 @@ func TestPendingLimiting(t *testing.T) { // Create a test account and fund it pool, key := setupPool() - defer pool.Stop() + defer pool.Close() account := crypto.PubkeyToAddress(key.PublicKey) testAddBalance(pool, account, big.NewInt(1000000000000)) @@ -1153,13 +1191,14 @@ func TestPendingGlobalLimiting(t *testing.T) { // Create the pool to test the limit enforcement with statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) + blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) config := testTxPoolConfig config.GlobalSlots = config.AccountSlots * 10 - pool := NewTxPool(config, params.TestChainConfig, blockchain) - defer pool.Stop() + pool := New(config, blockchain) + pool.Init(new(big.Int).SetUint64(config.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver()) + defer pool.Close() // Create a number of test accounts and fund them keys := make([]*ecdsa.PrivateKey, 5) @@ -1179,7 +1218,7 @@ func TestPendingGlobalLimiting(t *testing.T) { } } // Import the batch and verify that limits have been enforced - pool.AddRemotesSync(txs) + pool.addRemotesSync(txs) pending := 0 for _, list := range pool.pending { @@ -1201,7 +1240,7 @@ func TestAllowedTxSize(t *testing.T) { // Create a test account and fund it pool, key := setupPool() - defer pool.Stop() + defer pool.Close() account := crypto.PubkeyToAddress(key.PublicKey) testAddBalance(pool, account, big.NewInt(1000000000)) @@ -1210,7 +1249,7 @@ func TestAllowedTxSize(t *testing.T) { // // It is assumed the fields in the transaction (except of the data) are: // - nonce <= 32 bytes - // - gasPrice <= 32 bytes + // - gasTip <= 32 bytes // - gasLimit <= 32 bytes // - recipient == 20 bytes // - value <= 32 bytes @@ -1218,22 +1257,21 @@ func TestAllowedTxSize(t *testing.T) { // All those fields are summed up to at most 213 bytes. baseSize := uint64(213) dataSize := txMaxSize - baseSize - maxGas := pool.currentMaxGas.Load() // Try adding a transaction with maximal allowed size - tx := pricedDataTransaction(0, maxGas, big.NewInt(1), key, dataSize) + tx := pricedDataTransaction(0, pool.currentHead.Load().GasLimit, big.NewInt(1), key, dataSize) if err := pool.addRemoteSync(tx); err != nil { t.Fatalf("failed to add transaction of size %d, close to maximal: %v", int(tx.Size()), err) } // Try adding a transaction with random allowed size - if err := pool.addRemoteSync(pricedDataTransaction(1, maxGas, big.NewInt(1), key, uint64(rand.Intn(int(dataSize))))); err != nil { + if err := pool.addRemoteSync(pricedDataTransaction(1, pool.currentHead.Load().GasLimit, big.NewInt(1), key, uint64(rand.Intn(int(dataSize))))); err != nil { t.Fatalf("failed to add transaction of random allowed size: %v", err) } // Try adding a transaction of minimal not allowed size - if err := pool.addRemoteSync(pricedDataTransaction(2, maxGas, big.NewInt(1), key, txMaxSize)); err == nil { + if err := pool.addRemoteSync(pricedDataTransaction(2, pool.currentHead.Load().GasLimit, big.NewInt(1), key, txMaxSize)); err == nil { t.Fatalf("expected rejection on slightly oversize transaction") } // Try adding a transaction of random not allowed size - if err := pool.addRemoteSync(pricedDataTransaction(2, maxGas, big.NewInt(1), key, dataSize+1+uint64(rand.Intn(10*txMaxSize)))); err == nil { + if err := pool.addRemoteSync(pricedDataTransaction(2, pool.currentHead.Load().GasLimit, big.NewInt(1), key, dataSize+1+uint64(rand.Intn(10*txMaxSize)))); err == nil { t.Fatalf("expected rejection on oversize transaction") } // Run some sanity checks on the pool internals @@ -1255,15 +1293,16 @@ func TestCapClearsFromAll(t *testing.T) { // Create the pool to test the limit enforcement with statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) + blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) config := testTxPoolConfig config.AccountSlots = 2 config.AccountQueue = 2 config.GlobalSlots = 8 - pool := NewTxPool(config, params.TestChainConfig, blockchain) - defer pool.Stop() + pool := New(config, blockchain) + pool.Init(new(big.Int).SetUint64(config.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver()) + defer pool.Close() // Create a number of test accounts and fund them key, _ := crypto.GenerateKey() @@ -1275,7 +1314,7 @@ func TestCapClearsFromAll(t *testing.T) { txs = append(txs, transaction(uint64(j), 100000, key)) } // Import the batch and verify that limits have been enforced - pool.AddRemotes(txs) + pool.addRemotes(txs) if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } @@ -1289,13 +1328,14 @@ func TestPendingMinimumAllowance(t *testing.T) { // Create the pool to test the limit enforcement with statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) + blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) config := testTxPoolConfig config.GlobalSlots = 1 - pool := NewTxPool(config, params.TestChainConfig, blockchain) - defer pool.Stop() + pool := New(config, blockchain) + pool.Init(new(big.Int).SetUint64(config.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver()) + defer pool.Close() // Create a number of test accounts and fund them keys := make([]*ecdsa.PrivateKey, 5) @@ -1315,7 +1355,7 @@ func TestPendingMinimumAllowance(t *testing.T) { } } // Import the batch and verify that limits have been enforced - pool.AddRemotesSync(txs) + pool.addRemotesSync(txs) for addr, list := range pool.pending { if list.Len() != int(config.AccountSlots) { @@ -1337,10 +1377,11 @@ func TestRepricing(t *testing.T) { // Create the pool to test the pricing enforcement with statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) + blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) - pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain) - defer pool.Stop() + pool := New(testTxPoolConfig, blockchain) + pool.Init(new(big.Int).SetUint64(testTxPoolConfig.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver()) + defer pool.Close() // Keep track of transaction events to ensure all executables get announced events := make(chan core.NewTxsEvent, 32) @@ -1371,8 +1412,8 @@ func TestRepricing(t *testing.T) { ltx := pricedTransaction(0, 100000, big.NewInt(1), keys[3]) // Import the batch and that both pending and queued transactions match up - pool.AddRemotesSync(txs) - pool.AddLocal(ltx) + pool.addRemotesSync(txs) + pool.addLocal(ltx) pending, queued := pool.Stats() if pending != 7 { @@ -1388,7 +1429,7 @@ func TestRepricing(t *testing.T) { t.Fatalf("pool internal state corrupted: %v", err) } // Reprice the pool and check that underpriced transactions get dropped - pool.SetGasPrice(big.NewInt(2)) + pool.SetGasTip(big.NewInt(2)) pending, queued = pool.Stats() if pending != 2 { @@ -1404,14 +1445,14 @@ func TestRepricing(t *testing.T) { t.Fatalf("pool internal state corrupted: %v", err) } // Check that we can't add the old transactions back - if err := pool.AddRemote(pricedTransaction(1, 100000, big.NewInt(1), keys[0])); err != ErrUnderpriced { - t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, ErrUnderpriced) + if err := pool.addRemote(pricedTransaction(1, 100000, big.NewInt(1), keys[0])); !errors.Is(err, txpool.ErrUnderpriced) { + t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, txpool.ErrUnderpriced) } - if err := pool.AddRemote(pricedTransaction(0, 100000, big.NewInt(1), keys[1])); err != ErrUnderpriced { - t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, ErrUnderpriced) + if err := pool.addRemote(pricedTransaction(0, 100000, big.NewInt(1), keys[1])); !errors.Is(err, txpool.ErrUnderpriced) { + t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, txpool.ErrUnderpriced) } - if err := pool.AddRemote(pricedTransaction(2, 100000, big.NewInt(1), keys[2])); err != ErrUnderpriced { - t.Fatalf("adding underpriced queued transaction error mismatch: have %v, want %v", err, ErrUnderpriced) + if err := pool.addRemote(pricedTransaction(2, 100000, big.NewInt(1), keys[2])); !errors.Is(err, txpool.ErrUnderpriced) { + t.Fatalf("adding underpriced queued transaction error mismatch: have %v, want %v", err, txpool.ErrUnderpriced) } if err := validateEvents(events, 0); err != nil { t.Fatalf("post-reprice event firing failed: %v", err) @@ -1421,7 +1462,7 @@ func TestRepricing(t *testing.T) { } // However we can add local underpriced transactions tx := pricedTransaction(1, 100000, big.NewInt(1), keys[3]) - if err := pool.AddLocal(tx); err != nil { + if err := pool.addLocal(tx); err != nil { t.Fatalf("failed to add underpriced local transaction: %v", err) } if pending, _ = pool.Stats(); pending != 3 { @@ -1434,13 +1475,13 @@ func TestRepricing(t *testing.T) { t.Fatalf("pool internal state corrupted: %v", err) } // And we can fill gaps with properly priced transactions - if err := pool.AddRemote(pricedTransaction(1, 100000, big.NewInt(2), keys[0])); err != nil { + if err := pool.addRemote(pricedTransaction(1, 100000, big.NewInt(2), keys[0])); err != nil { t.Fatalf("failed to add pending transaction: %v", err) } - if err := pool.AddRemote(pricedTransaction(0, 100000, big.NewInt(2), keys[1])); err != nil { + if err := pool.addRemote(pricedTransaction(0, 100000, big.NewInt(2), keys[1])); err != nil { t.Fatalf("failed to add pending transaction: %v", err) } - if err := pool.AddRemote(pricedTransaction(2, 100000, big.NewInt(2), keys[2])); err != nil { + if err := pool.addRemoteSync(pricedTransaction(2, 100000, big.NewInt(2), keys[2])); err != nil { t.Fatalf("failed to add queued transaction: %v", err) } if err := validateEvents(events, 5); err != nil { @@ -1461,7 +1502,7 @@ func TestRepricingDynamicFee(t *testing.T) { // Create the pool to test the pricing enforcement with pool, _ := setupPoolWithConfig(eip1559Config) - defer pool.Stop() + defer pool.Close() // Keep track of transaction events to ensure all executables get announced events := make(chan core.NewTxsEvent, 32) @@ -1492,8 +1533,8 @@ func TestRepricingDynamicFee(t *testing.T) { ltx := dynamicFeeTx(0, 100000, big.NewInt(2), big.NewInt(1), keys[3]) // Import the batch and that both pending and queued transactions match up - pool.AddRemotesSync(txs) - pool.AddLocal(ltx) + pool.addRemotesSync(txs) + pool.addLocal(ltx) pending, queued := pool.Stats() if pending != 7 { @@ -1509,7 +1550,7 @@ func TestRepricingDynamicFee(t *testing.T) { t.Fatalf("pool internal state corrupted: %v", err) } // Reprice the pool and check that underpriced transactions get dropped - pool.SetGasPrice(big.NewInt(2)) + pool.SetGasTip(big.NewInt(2)) pending, queued = pool.Stats() if pending != 2 { @@ -1526,16 +1567,16 @@ func TestRepricingDynamicFee(t *testing.T) { } // Check that we can't add the old transactions back tx := pricedTransaction(1, 100000, big.NewInt(1), keys[0]) - if err := pool.AddRemote(tx); err != ErrUnderpriced { - t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, ErrUnderpriced) + if err := pool.addRemote(tx); !errors.Is(err, txpool.ErrUnderpriced) { + t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, txpool.ErrUnderpriced) } tx = dynamicFeeTx(0, 100000, big.NewInt(2), big.NewInt(1), keys[1]) - if err := pool.AddRemote(tx); err != ErrUnderpriced { - t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, ErrUnderpriced) + if err := pool.addRemote(tx); !errors.Is(err, txpool.ErrUnderpriced) { + t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, txpool.ErrUnderpriced) } tx = dynamicFeeTx(2, 100000, big.NewInt(1), big.NewInt(1), keys[2]) - if err := pool.AddRemote(tx); err != ErrUnderpriced { - t.Fatalf("adding underpriced queued transaction error mismatch: have %v, want %v", err, ErrUnderpriced) + if err := pool.addRemote(tx); !errors.Is(err, txpool.ErrUnderpriced) { + t.Fatalf("adding underpriced queued transaction error mismatch: have %v, want %v", err, txpool.ErrUnderpriced) } if err := validateEvents(events, 0); err != nil { t.Fatalf("post-reprice event firing failed: %v", err) @@ -1545,7 +1586,7 @@ func TestRepricingDynamicFee(t *testing.T) { } // However we can add local underpriced transactions tx = dynamicFeeTx(1, 100000, big.NewInt(1), big.NewInt(1), keys[3]) - if err := pool.AddLocal(tx); err != nil { + if err := pool.addLocal(tx); err != nil { t.Fatalf("failed to add underpriced local transaction: %v", err) } if pending, _ = pool.Stats(); pending != 3 { @@ -1559,15 +1600,15 @@ func TestRepricingDynamicFee(t *testing.T) { } // And we can fill gaps with properly priced transactions tx = pricedTransaction(1, 100000, big.NewInt(2), keys[0]) - if err := pool.AddRemote(tx); err != nil { + if err := pool.addRemote(tx); err != nil { t.Fatalf("failed to add pending transaction: %v", err) } tx = dynamicFeeTx(0, 100000, big.NewInt(3), big.NewInt(2), keys[1]) - if err := pool.AddRemote(tx); err != nil { + if err := pool.addRemote(tx); err != nil { t.Fatalf("failed to add pending transaction: %v", err) } tx = dynamicFeeTx(2, 100000, big.NewInt(2), big.NewInt(2), keys[2]) - if err := pool.AddRemote(tx); err != nil { + if err := pool.addRemoteSync(tx); err != nil { t.Fatalf("failed to add queued transaction: %v", err) } if err := validateEvents(events, 5); err != nil { @@ -1585,10 +1626,11 @@ func TestRepricingKeepsLocals(t *testing.T) { // Create the pool to test the pricing enforcement with statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) + blockchain := newTestBlockChain(eip1559Config, 1000000, statedb, new(event.Feed)) - pool := NewTxPool(testTxPoolConfig, eip1559Config, blockchain) - defer pool.Stop() + pool := New(testTxPoolConfig, blockchain) + pool.Init(new(big.Int).SetUint64(testTxPoolConfig.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver()) + defer pool.Close() // Create a number of test accounts and fund them keys := make([]*ecdsa.PrivateKey, 3) @@ -1600,23 +1642,23 @@ func TestRepricingKeepsLocals(t *testing.T) { for i := uint64(0); i < 500; i++ { // Add pending transaction. pendingTx := pricedTransaction(i, 100000, big.NewInt(int64(i)), keys[2]) - if err := pool.AddLocal(pendingTx); err != nil { + if err := pool.addLocal(pendingTx); err != nil { t.Fatal(err) } // Add queued transaction. queuedTx := pricedTransaction(i+501, 100000, big.NewInt(int64(i)), keys[2]) - if err := pool.AddLocal(queuedTx); err != nil { + if err := pool.addLocal(queuedTx); err != nil { t.Fatal(err) } // Add pending dynamic fee transaction. pendingTx = dynamicFeeTx(i, 100000, big.NewInt(int64(i)+1), big.NewInt(int64(i)), keys[1]) - if err := pool.AddLocal(pendingTx); err != nil { + if err := pool.addLocal(pendingTx); err != nil { t.Fatal(err) } // Add queued dynamic fee transaction. queuedTx = dynamicFeeTx(i+501, 100000, big.NewInt(int64(i)+1), big.NewInt(int64(i)), keys[1]) - if err := pool.AddLocal(queuedTx); err != nil { + if err := pool.addLocal(queuedTx); err != nil { t.Fatal(err) } } @@ -1638,13 +1680,13 @@ func TestRepricingKeepsLocals(t *testing.T) { validate() // Reprice the pool and check that nothing is dropped - pool.SetGasPrice(big.NewInt(2)) + pool.SetGasTip(big.NewInt(2)) validate() - pool.SetGasPrice(big.NewInt(2)) - pool.SetGasPrice(big.NewInt(4)) - pool.SetGasPrice(big.NewInt(8)) - pool.SetGasPrice(big.NewInt(100)) + pool.SetGasTip(big.NewInt(2)) + pool.SetGasTip(big.NewInt(4)) + pool.SetGasTip(big.NewInt(8)) + pool.SetGasTip(big.NewInt(100)) validate() } @@ -1658,14 +1700,15 @@ func TestUnderpricing(t *testing.T) { // Create the pool to test the pricing enforcement with statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) + blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) config := testTxPoolConfig config.GlobalSlots = 2 config.GlobalQueue = 2 - pool := NewTxPool(config, params.TestChainConfig, blockchain) - defer pool.Stop() + pool := New(config, blockchain) + pool.Init(new(big.Int).SetUint64(config.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver()) + defer pool.Close() // Keep track of transaction events to ensure all executables get announced events := make(chan core.NewTxsEvent, 32) @@ -1689,8 +1732,8 @@ func TestUnderpricing(t *testing.T) { ltx := pricedTransaction(0, 100000, big.NewInt(1), keys[2]) // Import the batch and that both pending and queued transactions match up - pool.AddRemotes(txs) - pool.AddLocal(ltx) + pool.addRemotes(txs) + pool.addLocal(ltx) pending, queued := pool.Stats() if pending != 3 { @@ -1706,26 +1749,26 @@ func TestUnderpricing(t *testing.T) { t.Fatalf("pool internal state corrupted: %v", err) } // Ensure that adding an underpriced transaction on block limit fails - if err := pool.AddRemote(pricedTransaction(0, 100000, big.NewInt(1), keys[1])); err != ErrUnderpriced { - t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, ErrUnderpriced) + if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1), keys[1])); !errors.Is(err, txpool.ErrUnderpriced) { + t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, txpool.ErrUnderpriced) } // Replace a future transaction with a future transaction - if err := pool.AddRemote(pricedTransaction(1, 100000, big.NewInt(2), keys[1])); err != nil { // +K1:1 => -K1:1 => Pend K0:0, K0:1, K2:0; Que K1:1 + if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(2), keys[1])); err != nil { // +K1:1 => -K1:1 => Pend K0:0, K0:1, K2:0; Que K1:1 t.Fatalf("failed to add well priced transaction: %v", err) } // Ensure that adding high priced transactions drops cheap ones, but not own - if err := pool.AddRemote(pricedTransaction(0, 100000, big.NewInt(3), keys[1])); err != nil { // +K1:0 => -K1:1 => Pend K0:0, K0:1, K1:0, K2:0; Que - + if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(3), keys[1])); err != nil { // +K1:0 => -K1:1 => Pend K0:0, K0:1, K1:0, K2:0; Que - t.Fatalf("failed to add well priced transaction: %v", err) } - if err := pool.AddRemote(pricedTransaction(2, 100000, big.NewInt(4), keys[1])); err != nil { // +K1:2 => -K0:0 => Pend K1:0, K2:0; Que K0:1 K1:2 + if err := pool.addRemoteSync(pricedTransaction(2, 100000, big.NewInt(4), keys[1])); err != nil { // +K1:2 => -K0:0 => Pend K1:0, K2:0; Que K0:1 K1:2 t.Fatalf("failed to add well priced transaction: %v", err) } - if err := pool.AddRemote(pricedTransaction(3, 100000, big.NewInt(5), keys[1])); err != nil { // +K1:3 => -K0:1 => Pend K1:0, K2:0; Que K1:2 K1:3 + if err := pool.addRemote(pricedTransaction(3, 100000, big.NewInt(5), keys[1])); err != nil { // +K1:3 => -K0:1 => Pend K1:0, K2:0; Que K1:2 K1:3 t.Fatalf("failed to add well priced transaction: %v", err) } // Ensure that replacing a pending transaction with a future transaction fails - if err := pool.AddRemote(pricedTransaction(5, 100000, big.NewInt(6), keys[1])); err != ErrFutureReplacePending { - t.Fatalf("adding future replace transaction error mismatch: have %v, want %v", err, ErrFutureReplacePending) + if err := pool.addRemote(pricedTransaction(5, 100000, big.NewInt(6), keys[1])); err != txpool.ErrFutureReplacePending { + t.Fatalf("adding future replace transaction error mismatch: have %v, want %v", err, txpool.ErrFutureReplacePending) } pending, queued = pool.Stats() if pending != 2 { @@ -1742,11 +1785,11 @@ func TestUnderpricing(t *testing.T) { } // Ensure that adding local transactions can push out even higher priced ones ltx = pricedTransaction(1, 100000, big.NewInt(0), keys[2]) - if err := pool.AddLocal(ltx); err != nil { + if err := pool.addLocal(ltx); err != nil { t.Fatalf("failed to append underpriced local transaction: %v", err) } ltx = pricedTransaction(0, 100000, big.NewInt(0), keys[3]) - if err := pool.AddLocal(ltx); err != nil { + if err := pool.addLocal(ltx); err != nil { t.Fatalf("failed to add new underpriced local transaction: %v", err) } pending, queued = pool.Stats() @@ -1772,14 +1815,15 @@ func TestStableUnderpricing(t *testing.T) { // Create the pool to test the pricing enforcement with statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) + blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) config := testTxPoolConfig config.GlobalSlots = 128 config.GlobalQueue = 0 - pool := NewTxPool(config, params.TestChainConfig, blockchain) - defer pool.Stop() + pool := New(config, blockchain) + pool.Init(new(big.Int).SetUint64(config.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver()) + defer pool.Close() // Keep track of transaction events to ensure all executables get announced events := make(chan core.NewTxsEvent, 32) @@ -1797,7 +1841,7 @@ func TestStableUnderpricing(t *testing.T) { for i := uint64(0); i < config.GlobalSlots; i++ { txs = append(txs, pricedTransaction(i, 100000, big.NewInt(1), keys[0])) } - pool.AddRemotesSync(txs) + pool.addRemotesSync(txs) pending, queued := pool.Stats() if pending != int(config.GlobalSlots) { @@ -1840,7 +1884,7 @@ func TestUnderpricingDynamicFee(t *testing.T) { t.Parallel() pool, _ := setupPoolWithConfig(eip1559Config) - defer pool.Stop() + defer pool.Close() pool.config.GlobalSlots = 2 pool.config.GlobalQueue = 2 @@ -1867,8 +1911,8 @@ func TestUnderpricingDynamicFee(t *testing.T) { ltx := dynamicFeeTx(0, 100000, big.NewInt(2), big.NewInt(1), keys[2]) // Import the batch and that both pending and queued transactions match up - pool.AddRemotes(txs) // Pend K0:0, K0:1; Que K1:1 - pool.AddLocal(ltx) // +K2:0 => Pend K0:0, K0:1, K2:0; Que K1:1 + pool.addRemotes(txs) // Pend K0:0, K0:1; Que K1:1 + pool.addLocal(ltx) // +K2:0 => Pend K0:0, K0:1, K2:0; Que K1:1 pending, queued := pool.Stats() if pending != 3 { @@ -1886,22 +1930,22 @@ func TestUnderpricingDynamicFee(t *testing.T) { // Ensure that adding an underpriced transaction fails tx := dynamicFeeTx(0, 100000, big.NewInt(2), big.NewInt(1), keys[1]) - if err := pool.AddRemote(tx); err != ErrUnderpriced { // Pend K0:0, K0:1, K2:0; Que K1:1 - t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, ErrUnderpriced) + if err := pool.addRemote(tx); !errors.Is(err, txpool.ErrUnderpriced) { // Pend K0:0, K0:1, K2:0; Que K1:1 + t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, txpool.ErrUnderpriced) } // Ensure that adding high priced transactions drops cheap ones, but not own tx = pricedTransaction(0, 100000, big.NewInt(2), keys[1]) - if err := pool.AddRemote(tx); err != nil { // +K1:0, -K1:1 => Pend K0:0, K0:1, K1:0, K2:0; Que - + if err := pool.addRemote(tx); err != nil { // +K1:0, -K1:1 => Pend K0:0, K0:1, K1:0, K2:0; Que - t.Fatalf("failed to add well priced transaction: %v", err) } tx = pricedTransaction(1, 100000, big.NewInt(3), keys[1]) - if err := pool.AddRemote(tx); err != nil { // +K1:2, -K0:1 => Pend K0:0 K1:0, K2:0; Que K1:2 + if err := pool.addRemoteSync(tx); err != nil { // +K1:2, -K0:1 => Pend K0:0 K1:0, K2:0; Que K1:2 t.Fatalf("failed to add well priced transaction: %v", err) } tx = dynamicFeeTx(2, 100000, big.NewInt(4), big.NewInt(1), keys[1]) - if err := pool.AddRemote(tx); err != nil { // +K1:3, -K1:0 => Pend K0:0 K2:0; Que K1:2 K1:3 + if err := pool.addRemoteSync(tx); err != nil { // +K1:3, -K1:0 => Pend K0:0 K2:0; Que K1:2 K1:3 t.Fatalf("failed to add well priced transaction: %v", err) } pending, queued = pool.Stats() @@ -1919,11 +1963,11 @@ func TestUnderpricingDynamicFee(t *testing.T) { } // Ensure that adding local transactions can push out even higher priced ones ltx = dynamicFeeTx(1, 100000, big.NewInt(0), big.NewInt(0), keys[2]) - if err := pool.AddLocal(ltx); err != nil { + if err := pool.addLocal(ltx); err != nil { t.Fatalf("failed to append underpriced local transaction: %v", err) } ltx = dynamicFeeTx(0, 100000, big.NewInt(0), big.NewInt(0), keys[3]) - if err := pool.AddLocal(ltx); err != nil { + if err := pool.addLocal(ltx); err != nil { t.Fatalf("failed to add new underpriced local transaction: %v", err) } pending, queued = pool.Stats() @@ -1947,7 +1991,7 @@ func TestDualHeapEviction(t *testing.T) { t.Parallel() pool, _ := setupPoolWithConfig(eip1559Config) - defer pool.Stop() + defer pool.Close() pool.config.GlobalSlots = 10 pool.config.GlobalQueue = 10 @@ -1976,7 +2020,7 @@ func TestDualHeapEviction(t *testing.T) { tx = dynamicFeeTx(0, 100000, big.NewInt(int64(baseFee+200+i)), big.NewInt(1), key) highCap = tx } - pool.AddRemotesSync([]*types.Transaction{tx}) + pool.addRemotesSync([]*types.Transaction{tx}) } pending, queued := pool.Stats() if pending+queued != 20 { @@ -2004,10 +2048,11 @@ func TestDeduplication(t *testing.T) { // Create the pool to test the pricing enforcement with statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) + blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) - pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain) - defer pool.Stop() + pool := New(testTxPoolConfig, blockchain) + pool.Init(new(big.Int).SetUint64(testTxPoolConfig.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver()) + defer pool.Close() // Create a test account to add transactions with key, _ := crypto.GenerateKey() @@ -2022,7 +2067,7 @@ func TestDeduplication(t *testing.T) { for i := 0; i < len(txs); i += 2 { firsts = append(firsts, txs[i]) } - errs := pool.AddRemotesSync(firsts) + errs := pool.addRemotesSync(firsts) if len(errs) != len(firsts) { t.Fatalf("first add mismatching result count: have %d, want %d", len(errs), len(firsts)) } @@ -2039,7 +2084,7 @@ func TestDeduplication(t *testing.T) { t.Fatalf("queued transactions mismatched: have %d, want %d", queued, len(txs)/2-1) } // Try to add all of them now and ensure previous ones error out as knowns - errs = pool.AddRemotesSync(txs) + errs = pool.addRemotesSync(txs) if len(errs) != len(txs) { t.Fatalf("all add mismatching result count: have %d, want %d", len(errs), len(txs)) } @@ -2070,10 +2115,11 @@ func TestReplacement(t *testing.T) { // Create the pool to test the pricing enforcement with statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) + blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) - pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain) - defer pool.Stop() + pool := New(testTxPoolConfig, blockchain) + pool.Init(new(big.Int).SetUint64(testTxPoolConfig.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver()) + defer pool.Close() // Keep track of transaction events to ensure all executables get announced events := make(chan core.NewTxsEvent, 32) @@ -2091,10 +2137,10 @@ func TestReplacement(t *testing.T) { if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1), key)); err != nil { t.Fatalf("failed to add original cheap pending transaction: %v", err) } - if err := pool.AddRemote(pricedTransaction(0, 100001, big.NewInt(1), key)); err != ErrReplaceUnderpriced { - t.Fatalf("original cheap pending transaction replacement error mismatch: have %v, want %v", err, ErrReplaceUnderpriced) + if err := pool.addRemote(pricedTransaction(0, 100001, big.NewInt(1), key)); err != txpool.ErrReplaceUnderpriced { + t.Fatalf("original cheap pending transaction replacement error mismatch: have %v, want %v", err, txpool.ErrReplaceUnderpriced) } - if err := pool.AddRemote(pricedTransaction(0, 100000, big.NewInt(2), key)); err != nil { + if err := pool.addRemote(pricedTransaction(0, 100000, big.NewInt(2), key)); err != nil { t.Fatalf("failed to replace original cheap pending transaction: %v", err) } if err := validateEvents(events, 2); err != nil { @@ -2104,10 +2150,10 @@ func TestReplacement(t *testing.T) { if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(price), key)); err != nil { t.Fatalf("failed to add original proper pending transaction: %v", err) } - if err := pool.AddRemote(pricedTransaction(0, 100001, big.NewInt(threshold-1), key)); err != ErrReplaceUnderpriced { - t.Fatalf("original proper pending transaction replacement error mismatch: have %v, want %v", err, ErrReplaceUnderpriced) + if err := pool.addRemote(pricedTransaction(0, 100001, big.NewInt(threshold-1), key)); err != txpool.ErrReplaceUnderpriced { + t.Fatalf("original proper pending transaction replacement error mismatch: have %v, want %v", err, txpool.ErrReplaceUnderpriced) } - if err := pool.AddRemote(pricedTransaction(0, 100000, big.NewInt(threshold), key)); err != nil { + if err := pool.addRemote(pricedTransaction(0, 100000, big.NewInt(threshold), key)); err != nil { t.Fatalf("failed to replace original proper pending transaction: %v", err) } if err := validateEvents(events, 2); err != nil { @@ -2115,23 +2161,23 @@ func TestReplacement(t *testing.T) { } // Add queued transactions, ensuring the minimum price bump is enforced for replacement (for ultra low prices too) - if err := pool.AddRemote(pricedTransaction(2, 100000, big.NewInt(1), key)); err != nil { + if err := pool.addRemote(pricedTransaction(2, 100000, big.NewInt(1), key)); err != nil { t.Fatalf("failed to add original cheap queued transaction: %v", err) } - if err := pool.AddRemote(pricedTransaction(2, 100001, big.NewInt(1), key)); err != ErrReplaceUnderpriced { - t.Fatalf("original cheap queued transaction replacement error mismatch: have %v, want %v", err, ErrReplaceUnderpriced) + if err := pool.addRemote(pricedTransaction(2, 100001, big.NewInt(1), key)); err != txpool.ErrReplaceUnderpriced { + t.Fatalf("original cheap queued transaction replacement error mismatch: have %v, want %v", err, txpool.ErrReplaceUnderpriced) } - if err := pool.AddRemote(pricedTransaction(2, 100000, big.NewInt(2), key)); err != nil { + if err := pool.addRemote(pricedTransaction(2, 100000, big.NewInt(2), key)); err != nil { t.Fatalf("failed to replace original cheap queued transaction: %v", err) } - if err := pool.AddRemote(pricedTransaction(2, 100000, big.NewInt(price), key)); err != nil { + if err := pool.addRemote(pricedTransaction(2, 100000, big.NewInt(price), key)); err != nil { t.Fatalf("failed to add original proper queued transaction: %v", err) } - if err := pool.AddRemote(pricedTransaction(2, 100001, big.NewInt(threshold-1), key)); err != ErrReplaceUnderpriced { - t.Fatalf("original proper queued transaction replacement error mismatch: have %v, want %v", err, ErrReplaceUnderpriced) + if err := pool.addRemote(pricedTransaction(2, 100001, big.NewInt(threshold-1), key)); err != txpool.ErrReplaceUnderpriced { + t.Fatalf("original proper queued transaction replacement error mismatch: have %v, want %v", err, txpool.ErrReplaceUnderpriced) } - if err := pool.AddRemote(pricedTransaction(2, 100000, big.NewInt(threshold), key)); err != nil { + if err := pool.addRemote(pricedTransaction(2, 100000, big.NewInt(threshold), key)); err != nil { t.Fatalf("failed to replace original proper queued transaction: %v", err) } @@ -2150,7 +2196,7 @@ func TestReplacementDynamicFee(t *testing.T) { // Create the pool to test the pricing enforcement with pool, key := setupPoolWithConfig(eip1559Config) - defer pool.Stop() + defer pool.Close() testAddBalance(pool, crypto.PubkeyToAddress(key.PublicKey), big.NewInt(1000000000)) // Keep track of transaction events to ensure all executables get announced @@ -2192,12 +2238,12 @@ func TestReplacementDynamicFee(t *testing.T) { } // 2. Don't bump tip or feecap => discard tx = dynamicFeeTx(nonce, 100001, big.NewInt(2), big.NewInt(1), key) - if err := pool.AddRemote(tx); err != ErrReplaceUnderpriced { - t.Fatalf("original cheap %s transaction replacement error mismatch: have %v, want %v", stage, err, ErrReplaceUnderpriced) + if err := pool.addRemote(tx); err != txpool.ErrReplaceUnderpriced { + t.Fatalf("original cheap %s transaction replacement error mismatch: have %v, want %v", stage, err, txpool.ErrReplaceUnderpriced) } // 3. Bump both more than min => accept tx = dynamicFeeTx(nonce, 100000, big.NewInt(3), big.NewInt(2), key) - if err := pool.AddRemote(tx); err != nil { + if err := pool.addRemote(tx); err != nil { t.Fatalf("failed to replace original cheap %s transaction: %v", stage, err) } // 4. Check events match expected (2 new executable txs during pending, 0 during queue) @@ -2215,27 +2261,27 @@ func TestReplacementDynamicFee(t *testing.T) { } // 6. Bump tip max allowed so it's still underpriced => discard tx = dynamicFeeTx(nonce, 100000, big.NewInt(gasFeeCap), big.NewInt(tipThreshold-1), key) - if err := pool.AddRemote(tx); err != ErrReplaceUnderpriced { - t.Fatalf("original proper %s transaction replacement error mismatch: have %v, want %v", stage, err, ErrReplaceUnderpriced) + if err := pool.addRemote(tx); err != txpool.ErrReplaceUnderpriced { + t.Fatalf("original proper %s transaction replacement error mismatch: have %v, want %v", stage, err, txpool.ErrReplaceUnderpriced) } // 7. Bump fee cap max allowed so it's still underpriced => discard tx = dynamicFeeTx(nonce, 100000, big.NewInt(feeCapThreshold-1), big.NewInt(gasTipCap), key) - if err := pool.AddRemote(tx); err != ErrReplaceUnderpriced { - t.Fatalf("original proper %s transaction replacement error mismatch: have %v, want %v", stage, err, ErrReplaceUnderpriced) + if err := pool.addRemote(tx); err != txpool.ErrReplaceUnderpriced { + t.Fatalf("original proper %s transaction replacement error mismatch: have %v, want %v", stage, err, txpool.ErrReplaceUnderpriced) } // 8. Bump tip min for acceptance => accept tx = dynamicFeeTx(nonce, 100000, big.NewInt(gasFeeCap), big.NewInt(tipThreshold), key) - if err := pool.AddRemote(tx); err != ErrReplaceUnderpriced { - t.Fatalf("original proper %s transaction replacement error mismatch: have %v, want %v", stage, err, ErrReplaceUnderpriced) + if err := pool.addRemote(tx); err != txpool.ErrReplaceUnderpriced { + t.Fatalf("original proper %s transaction replacement error mismatch: have %v, want %v", stage, err, txpool.ErrReplaceUnderpriced) } // 9. Bump fee cap min for acceptance => accept tx = dynamicFeeTx(nonce, 100000, big.NewInt(feeCapThreshold), big.NewInt(gasTipCap), key) - if err := pool.AddRemote(tx); err != ErrReplaceUnderpriced { - t.Fatalf("original proper %s transaction replacement error mismatch: have %v, want %v", stage, err, ErrReplaceUnderpriced) + if err := pool.addRemote(tx); err != txpool.ErrReplaceUnderpriced { + t.Fatalf("original proper %s transaction replacement error mismatch: have %v, want %v", stage, err, txpool.ErrReplaceUnderpriced) } // 10. Check events match expected (3 new executable txs during pending, 0 during queue) tx = dynamicFeeTx(nonce, 100000, big.NewInt(feeCapThreshold), big.NewInt(tipThreshold), key) - if err := pool.AddRemote(tx); err != nil { + if err := pool.addRemote(tx); err != nil { t.Fatalf("failed to replace original cheap %s transaction: %v", stage, err) } // 11. Check events match expected (3 new executable txs during pending, 0 during queue) @@ -2275,14 +2321,15 @@ func testJournaling(t *testing.T, nolocals bool) { // Create the original pool to inject transaction into the journal statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) + blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) config := testTxPoolConfig config.NoLocals = nolocals config.Journal = journal config.Rejournal = time.Second - pool := NewTxPool(config, params.TestChainConfig, blockchain) + pool := New(config, blockchain) + pool.Init(new(big.Int).SetUint64(config.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver()) // Create two test accounts to ensure remotes expire but locals do not local, _ := crypto.GenerateKey() @@ -2292,13 +2339,13 @@ func testJournaling(t *testing.T, nolocals bool) { testAddBalance(pool, crypto.PubkeyToAddress(remote.PublicKey), big.NewInt(1000000000)) // Add three local and a remote transactions and ensure they are queued up - if err := pool.AddLocal(pricedTransaction(0, 100000, big.NewInt(1), local)); err != nil { + if err := pool.addLocal(pricedTransaction(0, 100000, big.NewInt(1), local)); err != nil { t.Fatalf("failed to add local transaction: %v", err) } - if err := pool.AddLocal(pricedTransaction(1, 100000, big.NewInt(1), local)); err != nil { + if err := pool.addLocal(pricedTransaction(1, 100000, big.NewInt(1), local)); err != nil { t.Fatalf("failed to add local transaction: %v", err) } - if err := pool.AddLocal(pricedTransaction(2, 100000, big.NewInt(1), local)); err != nil { + if err := pool.addLocal(pricedTransaction(2, 100000, big.NewInt(1), local)); err != nil { t.Fatalf("failed to add local transaction: %v", err) } if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1), remote)); err != nil { @@ -2315,11 +2362,12 @@ func testJournaling(t *testing.T, nolocals bool) { t.Fatalf("pool internal state corrupted: %v", err) } // Terminate the old pool, bump the local nonce, create a new pool and ensure relevant transaction survive - pool.Stop() + pool.Close() statedb.SetNonce(crypto.PubkeyToAddress(local.PublicKey), 1) - blockchain = newTestBlockChain(1000000, statedb, new(event.Feed)) + blockchain = newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) - pool = NewTxPool(config, params.TestChainConfig, blockchain) + pool = New(config, blockchain) + pool.Init(new(big.Int).SetUint64(config.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver()) pending, queued = pool.Stats() if queued != 0 { @@ -2341,11 +2389,12 @@ func testJournaling(t *testing.T, nolocals bool) { statedb.SetNonce(crypto.PubkeyToAddress(local.PublicKey), 2) <-pool.requestReset(nil, nil) time.Sleep(2 * config.Rejournal) - pool.Stop() + pool.Close() statedb.SetNonce(crypto.PubkeyToAddress(local.PublicKey), 1) - blockchain = newTestBlockChain(1000000, statedb, new(event.Feed)) - pool = NewTxPool(config, params.TestChainConfig, blockchain) + blockchain = newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) + pool = New(config, blockchain) + pool.Init(new(big.Int).SetUint64(config.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver()) pending, queued = pool.Stats() if pending != 0 { @@ -2363,7 +2412,7 @@ func testJournaling(t *testing.T, nolocals bool) { if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } - pool.Stop() + pool.Close() } // TestStatusCheck tests that the pool can correctly retrieve the @@ -2373,10 +2422,11 @@ func TestStatusCheck(t *testing.T) { // Create the pool to test the status retrievals with statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) + blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) - pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain) - defer pool.Stop() + pool := New(testTxPoolConfig, blockchain) + pool.Init(new(big.Int).SetUint64(testTxPoolConfig.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver()) + defer pool.Close() // Create the test accounts to check various transaction statuses with keys := make([]*ecdsa.PrivateKey, 3) @@ -2393,7 +2443,7 @@ func TestStatusCheck(t *testing.T) { txs = append(txs, pricedTransaction(2, 100000, big.NewInt(1), keys[2])) // Queued only // Import the transaction and ensure they are correctly added - pool.AddRemotesSync(txs) + pool.addRemotesSync(txs) pending, queued := pool.Stats() if pending != 2 { @@ -2411,13 +2461,11 @@ func TestStatusCheck(t *testing.T) { hashes[i] = tx.Hash() } hashes = append(hashes, common.Hash{}) + expect := []txpool.TxStatus{txpool.TxStatusPending, txpool.TxStatusPending, txpool.TxStatusQueued, txpool.TxStatusQueued, txpool.TxStatusUnknown} - statuses := pool.Status(hashes) - expect := []TxStatus{TxStatusPending, TxStatusPending, TxStatusQueued, TxStatusQueued, TxStatusUnknown} - - for i := 0; i < len(statuses); i++ { - if statuses[i] != expect[i] { - t.Errorf("transaction %d: status mismatch: have %v, want %v", i, statuses[i], expect[i]) + for i := 0; i < len(hashes); i++ { + if status := pool.Status(hashes[i]); status != expect[i] { + t.Errorf("transaction %d: status mismatch: have %v, want %v", i, status, expect[i]) } } } @@ -2449,7 +2497,7 @@ func BenchmarkPendingDemotion10000(b *testing.B) { benchmarkPendingDemotion(b, 1 func benchmarkPendingDemotion(b *testing.B, size int) { // Add a batch of transactions to a pool one by one pool, key := setupPool() - defer pool.Stop() + defer pool.Close() account := crypto.PubkeyToAddress(key.PublicKey) testAddBalance(pool, account, big.NewInt(1000000)) @@ -2474,7 +2522,7 @@ func BenchmarkFuturePromotion10000(b *testing.B) { benchmarkFuturePromotion(b, 1 func benchmarkFuturePromotion(b *testing.B, size int) { // Add a batch of transactions to a pool one by one pool, key := setupPool() - defer pool.Stop() + defer pool.Close() account := crypto.PubkeyToAddress(key.PublicKey) testAddBalance(pool, account, big.NewInt(1000000)) @@ -2502,7 +2550,7 @@ func BenchmarkBatchLocalInsert10000(b *testing.B) { benchmarkBatchInsert(b, 1000 func benchmarkBatchInsert(b *testing.B, size int, local bool) { // Generate a batch of transactions to enqueue into the pool pool, key := setupPool() - defer pool.Stop() + defer pool.Close() account := crypto.PubkeyToAddress(key.PublicKey) testAddBalance(pool, account, big.NewInt(1000000000000000000)) @@ -2518,9 +2566,9 @@ func benchmarkBatchInsert(b *testing.B, size int, local bool) { b.ResetTimer() for _, batch := range batches { if local { - pool.AddLocals(batch) + pool.addLocals(batch) } else { - pool.AddRemotes(batch) + pool.addRemotes(batch) } } } @@ -2548,15 +2596,15 @@ func BenchmarkInsertRemoteWithAllLocals(b *testing.B) { pool, _ := setupPool() testAddBalance(pool, account, big.NewInt(100000000)) for _, local := range locals { - pool.AddLocal(local) + pool.addLocal(local) } b.StartTimer() // Assign a high enough balance for testing testAddBalance(pool, remoteAddr, big.NewInt(100000000)) for i := 0; i < len(remotes); i++ { - pool.AddRemotes([]*types.Transaction{remotes[i]}) + pool.addRemotes([]*types.Transaction{remotes[i]}) } - pool.Stop() + pool.Close() } } @@ -2564,7 +2612,7 @@ func BenchmarkInsertRemoteWithAllLocals(b *testing.B) { func BenchmarkMultiAccountBatchInsert(b *testing.B) { // Generate a batch of transactions to enqueue into the pool pool, _ := setupPool() - defer pool.Stop() + defer pool.Close() b.ReportAllocs() batches := make(types.Transactions, b.N) for i := 0; i < b.N; i++ { @@ -2577,6 +2625,6 @@ func BenchmarkMultiAccountBatchInsert(b *testing.B) { // Benchmark importing the transactions into the queue b.ResetTimer() for _, tx := range batches { - pool.AddRemotesSync([]*types.Transaction{tx}) + pool.addRemotesSync([]*types.Transaction{tx}) } } diff --git a/core/txpool/list.go b/core/txpool/legacypool/list.go similarity index 96% rename from core/txpool/list.go rename to core/txpool/legacypool/list.go index fae7c2fcac..384fa7b61b 100644 --- a/core/txpool/list.go +++ b/core/txpool/legacypool/list.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 txpool +package legacypool import ( "container/heap" @@ -53,9 +53,10 @@ func (h *nonceHeap) Pop() interface{} { // sortedMap is a nonce->transaction hash map with a heap based index to allow // iterating over the contents in a nonce-incrementing way. type sortedMap struct { - items map[uint64]*types.Transaction // Hash map storing the transaction data - index *nonceHeap // Heap of nonces of all the stored transactions (non-strict mode) - cache types.Transactions // Cache of the transactions already sorted + items map[uint64]*types.Transaction // Hash map storing the transaction data + index *nonceHeap // Heap of nonces of all the stored transactions (non-strict mode) + cache types.Transactions // Cache of the transactions already sorted + cacheMu sync.Mutex // Mutex covering the cache } // newSortedMap creates a new nonce-sorted transaction map. @@ -78,7 +79,9 @@ func (m *sortedMap) Put(tx *types.Transaction) { if m.items[nonce] == nil { heap.Push(m.index, nonce) } + m.cacheMu.Lock() m.items[nonce], m.cache = tx, nil + m.cacheMu.Unlock() } // Forward removes all transactions from the map with a nonce lower than the @@ -94,9 +97,11 @@ func (m *sortedMap) Forward(threshold uint64) types.Transactions { delete(m.items, nonce) } // If we had a cached order, shift the front + m.cacheMu.Lock() if m.cache != nil { m.cache = m.cache[len(removed):] } + m.cacheMu.Unlock() return removed } @@ -120,7 +125,9 @@ func (m *sortedMap) reheap() { *m.index = append(*m.index, nonce) } heap.Init(m.index) + m.cacheMu.Lock() m.cache = nil + m.cacheMu.Unlock() } // filter is identical to Filter, but **does not** regenerate the heap. This method @@ -136,7 +143,9 @@ func (m *sortedMap) filter(filter func(*types.Transaction) bool) types.Transacti } } if len(removed) > 0 { + m.cacheMu.Lock() m.cache = nil + m.cacheMu.Unlock() } return removed } @@ -160,9 +169,11 @@ func (m *sortedMap) Cap(threshold int) types.Transactions { heap.Init(m.index) // If we had a cache, shift the back + m.cacheMu.Lock() if m.cache != nil { m.cache = m.cache[:len(m.cache)-len(drops)] } + m.cacheMu.Unlock() return drops } @@ -182,7 +193,9 @@ func (m *sortedMap) Remove(nonce uint64) bool { } } delete(m.items, nonce) + m.cacheMu.Lock() m.cache = nil + m.cacheMu.Unlock() return true } @@ -206,7 +219,9 @@ func (m *sortedMap) Ready(start uint64) types.Transactions { delete(m.items, next) heap.Pop(m.index) } + m.cacheMu.Lock() m.cache = nil + m.cacheMu.Unlock() return ready } @@ -217,6 +232,8 @@ func (m *sortedMap) Len() int { } func (m *sortedMap) flatten() types.Transactions { + m.cacheMu.Lock() + defer m.cacheMu.Unlock() // If the sorting was not cached yet, create and cache it if m.cache == nil { m.cache = make(types.Transactions, 0, len(m.items)) @@ -232,8 +249,8 @@ func (m *sortedMap) flatten() types.Transactions { // sorted internal representation. The result of the sorting is cached in case // it's requested again before any modifications are made to the contents. func (m *sortedMap) Flatten() types.Transactions { - // Copy the cache to prevent accidental modifications cache := m.flatten() + // Copy the cache to prevent accidental modification txs := make(types.Transactions, len(cache)) copy(txs, cache) return txs @@ -590,7 +607,7 @@ func (l *pricedList) underpricedFor(h *priceHeap, tx *types.Transaction) bool { func (l *pricedList) Discard(slots int, force bool) (types.Transactions, bool) { drop := make(types.Transactions, 0, slots) // Remote underpriced transactions to drop for slots > 0 { - if len(l.urgent.list)*floatingRatio > len(l.floating.list)*urgentRatio || floatingRatio == 0 { + if len(l.urgent.list)*floatingRatio > len(l.floating.list)*urgentRatio { // Discard stale transactions if found during cleanup tx := heap.Pop(&l.urgent).(*types.Transaction) if l.all.GetRemote(tx.Hash()) == nil { // Removed or migrated diff --git a/core/txpool/list_test.go b/core/txpool/legacypool/list_test.go similarity index 99% rename from core/txpool/list_test.go rename to core/txpool/legacypool/list_test.go index 4e1a5d5e83..b5cd34b23b 100644 --- a/core/txpool/list_test.go +++ b/core/txpool/legacypool/list_test.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 txpool +package legacypool import ( "math/big" diff --git a/core/txpool/noncer.go b/core/txpool/legacypool/noncer.go similarity index 99% rename from core/txpool/noncer.go rename to core/txpool/legacypool/noncer.go index ba7fbedad5..2c65dd2cae 100644 --- a/core/txpool/noncer.go +++ b/core/txpool/legacypool/noncer.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 txpool +package legacypool import ( "sync" diff --git a/core/txpool/subpool.go b/core/txpool/subpool.go new file mode 100644 index 0000000000..85312c4318 --- /dev/null +++ b/core/txpool/subpool.go @@ -0,0 +1,127 @@ +// 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 txpool + +import ( + "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/event" +) + +// LazyTransaction contains a small subset of the transaction properties that is +// enough for the miner and other APIs to handle large batches of transactions; +// and supports pulling up the entire transaction when really needed. +type LazyTransaction struct { + Pool SubPool // Transaction subpool to pull the real transaction up + Hash common.Hash // Transaction hash to pull up if needed + Tx *types.Transaction // Transaction if already resolved + + Time time.Time // Time when the transaction was first seen + GasFeeCap *big.Int // Maximum fee per gas the transaction may consume + GasTipCap *big.Int // Maximum miner tip per gas the transaction can pay +} + +// Resolve retrieves the full transaction belonging to a lazy handle if it is still +// maintained by the transaction pool. +func (ltx *LazyTransaction) Resolve() *types.Transaction { + if ltx.Tx == nil { + ltx.Tx = ltx.Pool.Get(ltx.Hash) + } + return ltx.Tx +} + +// AddressReserver is passed by the main transaction pool to subpools, so they +// may request (and relinquish) exclusive access to certain addresses. +type AddressReserver func(addr common.Address, reserve bool) error + +// SubPool represents a specialized transaction pool that lives on its own (e.g. +// blob pool). Since independent of how many specialized pools we have, they do +// need to be updated in lockstep and assemble into one coherent view for block +// production, this interface defines the common methods that allow the primary +// transaction pool to manage the subpools. +type SubPool interface { + // Filter is a selector used to decide whether a transaction whould be added + // to this particular subpool. + Filter(tx *types.Transaction) bool + + // Init sets the base parameters of the subpool, allowing it to load any saved + // transactions from disk and also permitting internal maintenance routines to + // start up. + // + // These should not be passed as a constructor argument - nor should the pools + // start by themselves - in order to keep multiple subpools in lockstep with + // one another. + Init(gasTip *big.Int, head *types.Header, reserve AddressReserver) error + + // Close terminates any background processing threads and releases any held + // resources. + Close() error + + // Reset retrieves the current state of the blockchain and ensures the content + // of the transaction pool is valid with regard to the chain state. + Reset(oldHead, newHead *types.Header) + + // SetGasTip updates the minimum price required by the subpool for a new + // transaction, and drops all transactions below this threshold. + SetGasTip(tip *big.Int) + + // Has returns an indicator whether subpool has a transaction cached with the + // given hash. + Has(hash common.Hash) bool + + // Get returns a transaction if it is contained in the pool, or nil otherwise. + Get(hash common.Hash) *types.Transaction + + // Add enqueues a batch of transactions into the pool if they are valid. Due + // to the large transaction churn, add may postpone fully integrating the tx + // to a later point to batch multiple ones together. + Add(txs []*types.Transaction, local bool, sync bool) []error + + // Pending retrieves all currently processable transactions, grouped by origin + // account and sorted by nonce. + Pending(enforceTips bool) map[common.Address][]*LazyTransaction + + // SubscribeTransactions subscribes to new transaction events. + SubscribeTransactions(ch chan<- core.NewTxsEvent) event.Subscription + + // Nonce returns the next nonce of an account, with all transactions executable + // by the pool already applied on top. + Nonce(addr common.Address) uint64 + + // Stats retrieves the current pool stats, namely the number of pending and the + // number of queued (non-executable) transactions. + Stats() (int, int) + + // Content retrieves the data content of the transaction pool, returning all the + // pending as well as queued transactions, grouped by account and sorted by nonce. + Content() (map[common.Address][]*types.Transaction, map[common.Address][]*types.Transaction) + + // ContentFrom retrieves the data content of the transaction pool, returning the + // pending as well as queued transactions of this address, grouped by nonce. + ContentFrom(addr common.Address) ([]*types.Transaction, []*types.Transaction) + + // Locals retrieves the accounts currently considered local by the pool. + Locals() []common.Address + + // Status returns the known status (unknown/pending/queued) of a transaction + // identified by their hashes. + Status(hash common.Hash) TxStatus +} diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go index 056b1ebe87..e40b414054 100644 --- a/core/txpool/txpool.go +++ b/core/txpool/txpool.go @@ -1,4 +1,4 @@ -// Copyright 2014 The go-ethereum Authors +// 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 @@ -19,125 +19,15 @@ package txpool import ( "errors" "fmt" - "math" "math/big" - "sort" "sync" - "sync/atomic" - "time" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/prque" - "github.com/ethereum/go-ethereum/consensus/misc" "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" "github.com/ethereum/go-ethereum/metrics" - "github.com/ethereum/go-ethereum/params" -) - -const ( - // chainHeadChanSize is the size of channel listening to ChainHeadEvent. - chainHeadChanSize = 10 - - // txSlotSize is used to calculate how many data slots a single transaction - // takes up based on its size. The slots are used as DoS protection, ensuring - // that validating a new transaction remains a constant operation (in reality - // O(maxslots), where max slots are 4 currently). - txSlotSize = 32 * 1024 - - // txMaxSize is the maximum size a single transaction can have. This field has - // non-trivial consequences: larger transactions are significantly harder and - // more expensive to propagate; larger transactions also take more resources - // to validate whether they fit into the pool or not. - txMaxSize = 4 * txSlotSize // 128KB -) - -var ( - // ErrAlreadyKnown is returned if the transactions is already contained - // within the pool. - ErrAlreadyKnown = errors.New("already known") - - // ErrInvalidSender is returned if the transaction contains an invalid signature. - ErrInvalidSender = errors.New("invalid sender") - - // ErrUnderpriced is returned if a transaction's gas price is below the minimum - // configured for the transaction pool. - ErrUnderpriced = errors.New("transaction underpriced") - - // ErrTxPoolOverflow is returned if the transaction pool is full and can't accept - // another remote transaction. - ErrTxPoolOverflow = errors.New("txpool is full") - - // ErrReplaceUnderpriced is returned if a transaction is attempted to be replaced - // with a different one without the required price bump. - ErrReplaceUnderpriced = errors.New("replacement transaction underpriced") - - // ErrGasLimit is returned if a transaction's requested gas limit exceeds the - // maximum allowance of the current block. - ErrGasLimit = errors.New("exceeds block gas limit") - - // ErrNegativeValue is a sanity error to ensure no one is able to specify a - // transaction with a negative value. - ErrNegativeValue = errors.New("negative value") - - // ErrOversizedData is returned if the input data of a transaction is greater - // than some meaningful limit a user might use. This is not a consensus error - // making the transaction invalid, rather a DOS protection. - ErrOversizedData = errors.New("oversized data") - - // ErrFutureReplacePending is returned if a future transaction replaces a pending - // transaction. Future transactions should only be able to replace other future transactions. - ErrFutureReplacePending = errors.New("future transaction tries to replace pending") - - // ErrOverdraft is returned if a transaction would cause the senders balance to go negative - // thus invalidating a potential large number of transactions. - ErrOverdraft = errors.New("transaction would cause overdraft") -) - -var ( - evictionInterval = time.Minute // Time interval to check for evictable transactions - statsReportInterval = 8 * time.Second // Time interval to report transaction pool stats -) - -var ( - // Metrics for the pending pool - pendingDiscardMeter = metrics.NewRegisteredMeter("txpool/pending/discard", nil) - pendingReplaceMeter = metrics.NewRegisteredMeter("txpool/pending/replace", nil) - pendingRateLimitMeter = metrics.NewRegisteredMeter("txpool/pending/ratelimit", nil) // Dropped due to rate limiting - pendingNofundsMeter = metrics.NewRegisteredMeter("txpool/pending/nofunds", nil) // Dropped due to out-of-funds - - // Metrics for the queued pool - queuedDiscardMeter = metrics.NewRegisteredMeter("txpool/queued/discard", nil) - queuedReplaceMeter = metrics.NewRegisteredMeter("txpool/queued/replace", nil) - queuedRateLimitMeter = metrics.NewRegisteredMeter("txpool/queued/ratelimit", nil) // Dropped due to rate limiting - queuedNofundsMeter = metrics.NewRegisteredMeter("txpool/queued/nofunds", nil) // Dropped due to out-of-funds - queuedEvictionMeter = metrics.NewRegisteredMeter("txpool/queued/eviction", nil) // Dropped due to lifetime - - // General tx metrics - knownTxMeter = metrics.NewRegisteredMeter("txpool/known", nil) - validTxMeter = metrics.NewRegisteredMeter("txpool/valid", nil) - invalidTxMeter = metrics.NewRegisteredMeter("txpool/invalid", nil) - underpricedTxMeter = metrics.NewRegisteredMeter("txpool/underpriced", nil) - overflowedTxMeter = metrics.NewRegisteredMeter("txpool/overflowed", nil) - - // throttleTxMeter counts how many transactions are rejected due to too-many-changes between - // txpool reorgs. - throttleTxMeter = metrics.NewRegisteredMeter("txpool/throttle", nil) - // reorgDurationTimer measures how long time a txpool reorg takes. - reorgDurationTimer = metrics.NewRegisteredTimer("txpool/reorgtime", nil) - // dropBetweenReorgHistogram counts how many drops we experience between two reorg runs. It is expected - // that this number is pretty low, since txpool reorgs happen very frequently. - dropBetweenReorgHistogram = metrics.NewRegisteredHistogram("txpool/dropbetweenreorg", nil, metrics.NewExpDecaySample(1028, 0.015)) - - pendingGauge = metrics.NewRegisteredGauge("txpool/pending", nil) - queuedGauge = metrics.NewRegisteredGauge("txpool/queued", nil) - localGauge = metrics.NewRegisteredGauge("txpool/local", nil) - slotsGauge = metrics.NewRegisteredGauge("txpool/slots", nil) - - reheapTimer = metrics.NewRegisteredTimer("txpool/reheap", nil) ) // TxStatus is the current status of a transaction as seen by the pool. @@ -150,1768 +40,376 @@ const ( TxStatusIncluded ) -// blockChain provides the state of blockchain and current gas limit to do -// some pre checks in tx pool and event subscribers. -type blockChain interface { - CurrentBlock() *types.Header - GetBlock(hash common.Hash, number uint64) *types.Block - StateAt(root common.Hash) (*state.StateDB, error) +var ( + // reservationsGaugeName is the prefix of a per-subpool address reservation + // metric. + // + // This is mostly a sanity metric to ensure there's no bug that would make + // some subpool hog all the reservations due to mis-accounting. + reservationsGaugeName = "txpool/reservations" +) +// BlockChain defines the minimal set of methods needed to back a tx pool with +// a chain. Exists to allow mocking the live chain out of tests. +type BlockChain interface { + // CurrentBlock returns the current head of the chain. + CurrentBlock() *types.Header + + // SubscribeChainHeadEvent subscribes to new blocks being added to the chain. SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription } -// Config are the configuration parameters of the transaction pool. -type Config struct { - Locals []common.Address // Addresses that should be treated by default as local - NoLocals bool // Whether local transaction handling should be disabled - Journal string // Journal of local transactions to survive node restarts - Rejournal time.Duration // Time interval to regenerate the local transaction journal - - PriceLimit uint64 // Minimum gas price to enforce for acceptance into the pool - PriceBump uint64 // Minimum price bump percentage to replace an already existing transaction (nonce) - - AccountSlots uint64 // Number of executable transaction slots guaranteed per account - GlobalSlots uint64 // Maximum number of executable transaction slots for all accounts - AccountQueue uint64 // Maximum number of non-executable transaction slots permitted per account - GlobalQueue uint64 // Maximum number of non-executable transaction slots for all accounts - - Lifetime time.Duration // Maximum amount of time non-executable transaction are queued -} - -// DefaultConfig contains the default configurations for the transaction -// pool. -var DefaultConfig = Config{ - Journal: "transactions.rlp", - Rejournal: time.Hour, - - PriceLimit: 1, - PriceBump: 10, - - AccountSlots: 16, - GlobalSlots: 4096 + 1024, // urgent + floating queue capacity with 4:1 ratio - AccountQueue: 64, - GlobalQueue: 1024, - - Lifetime: 3 * time.Hour, -} - -// sanitize checks the provided user configurations and changes anything that's -// unreasonable or unworkable. -func (config *Config) sanitize() Config { - conf := *config - if conf.Rejournal < time.Second { - log.Warn("Sanitizing invalid txpool journal time", "provided", conf.Rejournal, "updated", time.Second) - conf.Rejournal = time.Second - } - if conf.PriceLimit < 1 { - log.Warn("Sanitizing invalid txpool price limit", "provided", conf.PriceLimit, "updated", DefaultConfig.PriceLimit) - conf.PriceLimit = DefaultConfig.PriceLimit - } - if conf.PriceBump < 1 { - log.Warn("Sanitizing invalid txpool price bump", "provided", conf.PriceBump, "updated", DefaultConfig.PriceBump) - conf.PriceBump = DefaultConfig.PriceBump - } - if conf.AccountSlots < 1 { - log.Warn("Sanitizing invalid txpool account slots", "provided", conf.AccountSlots, "updated", DefaultConfig.AccountSlots) - conf.AccountSlots = DefaultConfig.AccountSlots - } - if conf.GlobalSlots < 1 { - log.Warn("Sanitizing invalid txpool global slots", "provided", conf.GlobalSlots, "updated", DefaultConfig.GlobalSlots) - conf.GlobalSlots = DefaultConfig.GlobalSlots - } - if conf.AccountQueue < 1 { - log.Warn("Sanitizing invalid txpool account queue", "provided", conf.AccountQueue, "updated", DefaultConfig.AccountQueue) - conf.AccountQueue = DefaultConfig.AccountQueue - } - if conf.GlobalQueue < 1 { - log.Warn("Sanitizing invalid txpool global queue", "provided", conf.GlobalQueue, "updated", DefaultConfig.GlobalQueue) - conf.GlobalQueue = DefaultConfig.GlobalQueue - } - if conf.Lifetime < 1 { - log.Warn("Sanitizing invalid txpool lifetime", "provided", conf.Lifetime, "updated", DefaultConfig.Lifetime) - conf.Lifetime = DefaultConfig.Lifetime - } - return conf -} - -// TxPool contains all currently known transactions. Transactions -// enter the pool when they are received from the network or submitted -// locally. They exit the pool when they are included in the blockchain. -// -// The pool separates processable transactions (which can be applied to the -// current state) and future transactions. Transactions move between those -// two states over time as they are received and processed. +// TxPool is an aggregator for various transaction specific pools, collectively +// tracking all the transactions deemed interesting by the node. Transactions +// enter the pool when they are received from the network or submitted locally. +// They exit the pool when they are included in the blockchain or evicted due to +// resource constraints. type TxPool struct { - config Config - chainconfig *params.ChainConfig - chain blockChain - gasPrice *big.Int - txFeed event.Feed - scope event.SubscriptionScope - signer types.Signer - mu sync.RWMutex + subpools []SubPool // List of subpools for specialized transaction handling - istanbul atomic.Bool // Fork indicator whether we are in the istanbul stage. - eip2718 atomic.Bool // Fork indicator whether we are using EIP-2718 type transactions. - eip1559 atomic.Bool // Fork indicator whether we are using EIP-1559 type transactions. - shanghai atomic.Bool // Fork indicator whether we are in the Shanghai stage. + reservations map[common.Address]SubPool // Map with the account to pool reservations + reserveLock sync.Mutex // Lock protecting the account reservations - currentState *state.StateDB // Current state in the blockchain head - pendingNonces *noncer // Pending state tracking virtual nonces - currentMaxGas atomic.Uint64 // Current gas limit for transaction caps - - locals *accountSet // Set of local transaction to exempt from eviction rules - journal *journal // Journal of local transaction to back up to disk - - pending map[common.Address]*list // All currently processable transactions - queue map[common.Address]*list // Queued but non-processable transactions - beats map[common.Address]time.Time // Last heartbeat from each known account - all *lookup // All transactions to allow lookups - priced *pricedList // All transactions sorted by price - - chainHeadCh chan core.ChainHeadEvent - chainHeadSub event.Subscription - reqResetCh chan *txpoolResetRequest - reqPromoteCh chan *accountSet - queueTxEventCh chan *types.Transaction - reorgDoneCh chan chan struct{} - reorgShutdownCh chan struct{} // requests shutdown of scheduleReorgLoop - wg sync.WaitGroup // tracks loop, scheduleReorgLoop - initDoneCh chan struct{} // is closed once the pool is initialized (for tests) - - changesSinceReorg int // A counter for how many drops we've performed in-between reorg. + subs event.SubscriptionScope // Subscription scope to unscubscribe all on shutdown + quit chan chan error // Quit channel to tear down the head updater } -type txpoolResetRequest struct { - oldHead, newHead *types.Header -} - -// NewTxPool creates a new transaction pool to gather, sort and filter inbound +// New creates a new transaction pool to gather, sort and filter inbound // transactions from the network. -func NewTxPool(config Config, chainconfig *params.ChainConfig, chain blockChain) *TxPool { - // Sanitize the input to ensure no vulnerable gas prices are set - config = (&config).sanitize() +func New(gasTip *big.Int, chain BlockChain, subpools []SubPool) (*TxPool, error) { + // Retrieve the current head so that all subpools and this main coordinator + // pool will have the same starting state, even if the chain moves forward + // during initialization. + head := chain.CurrentBlock() - // Create the transaction pool with its initial settings pool := &TxPool{ - config: config, - chainconfig: chainconfig, - chain: chain, - signer: types.LatestSigner(chainconfig), - pending: make(map[common.Address]*list), - queue: make(map[common.Address]*list), - beats: make(map[common.Address]time.Time), - all: newLookup(), - chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize), - reqResetCh: make(chan *txpoolResetRequest), - reqPromoteCh: make(chan *accountSet), - queueTxEventCh: make(chan *types.Transaction), - reorgDoneCh: make(chan chan struct{}), - reorgShutdownCh: make(chan struct{}), - initDoneCh: make(chan struct{}), - gasPrice: new(big.Int).SetUint64(config.PriceLimit), + subpools: subpools, + reservations: make(map[common.Address]SubPool), + quit: make(chan chan error), } - pool.locals = newAccountSet(pool.signer) - for _, addr := range config.Locals { - log.Info("Setting new local account", "address", addr) - pool.locals.add(addr) - } - pool.priced = newPricedList(pool.all) - pool.reset(nil, chain.CurrentBlock()) - - // Start the reorg loop early so it can handle requests generated during journal loading. - pool.wg.Add(1) - go pool.scheduleReorgLoop() - - // If local transactions and journaling is enabled, load from disk - if !config.NoLocals && config.Journal != "" { - pool.journal = newTxJournal(config.Journal) - - if err := pool.journal.load(pool.AddLocals); err != nil { - log.Warn("Failed to load transaction journal", "err", err) - } - if err := pool.journal.rotate(pool.local()); err != nil { - log.Warn("Failed to rotate transaction journal", "err", err) + for i, subpool := range subpools { + if err := subpool.Init(gasTip, head, pool.reserver(i, subpool)); err != nil { + for j := i - 1; j >= 0; j-- { + subpools[j].Close() + } + return nil, err } } + go pool.loop(head, chain) + return pool, nil +} - // Subscribe events from blockchain and start the main event loop. - pool.chainHeadSub = pool.chain.SubscribeChainHeadEvent(pool.chainHeadCh) - pool.wg.Add(1) - go pool.loop() +// 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 +// subpool eviction issues and nonce conflicts. +func (p *TxPool) reserver(id int, subpool SubPool) AddressReserver { + return func(addr common.Address, reserve bool) error { + p.reserveLock.Lock() + defer p.reserveLock.Unlock() - return pool + owner, exists := p.reservations[addr] + if reserve { + // Double reservations are forbidden even from the same pool to + // avoid subtle bugs in the long term. + if exists { + if owner == subpool { + log.Error("pool attempted to reserve already-owned address", "address", addr) + return nil // Ignore fault to give the pool a chance to recover while the bug gets fixed + } + return errors.New("address already reserved") + } + p.reservations[addr] = subpool + if metrics.Enabled { + m := fmt.Sprintf("%s/%d", reservationsGaugeName, id) + metrics.GetOrRegisterGauge(m, nil).Inc(1) + } + return nil + } + // Ensure subpools only attempt to unreserve their own owned addresses, + // otherwise flag as a programming error. + if !exists { + log.Error("pool attempted to unreserve non-reserved address", "address", addr) + return errors.New("address not reserved") + } + if subpool != owner { + log.Error("pool attempted to unreserve non-owned address", "address", addr) + return errors.New("address not owned") + } + delete(p.reservations, addr) + if metrics.Enabled { + m := fmt.Sprintf("%s/%d", reservationsGaugeName, id) + metrics.GetOrRegisterGauge(m, nil).Dec(1) + } + return nil + } +} + +// Close terminates the transaction pool and all its subpools. +func (p *TxPool) Close() error { + var errs []error + + // Terminate the reset loop and wait for it to finish + errc := make(chan error) + p.quit <- errc + if err := <-errc; err != nil { + errs = append(errs, err) + } + + // Terminate each subpool + for _, subpool := range p.subpools { + if err := subpool.Close(); err != nil { + errs = append(errs, err) + } + } + if len(errs) > 0 { + return fmt.Errorf("subpool close errors: %v", errs) + } + return nil } // loop is the transaction pool's main event loop, waiting for and reacting to // outside blockchain events as well as for various reporting and transaction // eviction events. -func (pool *TxPool) loop() { - defer pool.wg.Done() - +func (p *TxPool) loop(head *types.Header, chain BlockChain) { + // Subscribe to chain head events to trigger subpool resets var ( - prevPending, prevQueued, prevStales int - // Start the stats reporting and transaction eviction tickers - report = time.NewTicker(statsReportInterval) - evict = time.NewTicker(evictionInterval) - journal = time.NewTicker(pool.config.Rejournal) - // Track the previous head headers for transaction reorgs - head = pool.chain.CurrentBlock() + newHeadCh = make(chan core.ChainHeadEvent) + newHeadSub = chain.SubscribeChainHeadEvent(newHeadCh) ) - defer report.Stop() - defer evict.Stop() - defer journal.Stop() + defer newHeadSub.Unsubscribe() - // Notify tests that the init phase is done - close(pool.initDoneCh) - for { - select { - // Handle ChainHeadEvent - case ev := <-pool.chainHeadCh: - if ev.Block != nil { - pool.requestReset(head, ev.Block.Header()) - head = ev.Block.Header() - } - - // System shutdown. - case <-pool.chainHeadSub.Err(): - close(pool.reorgShutdownCh) - return - - // Handle stats reporting ticks - case <-report.C: - pool.mu.RLock() - pending, queued := pool.stats() - pool.mu.RUnlock() - stales := int(pool.priced.stales.Load()) - - if pending != prevPending || queued != prevQueued || stales != prevStales { - log.Debug("Transaction pool status report", "executable", pending, "queued", queued, "stales", stales) - prevPending, prevQueued, prevStales = pending, queued, stales - } - - // Handle inactive account transaction eviction - case <-evict.C: - pool.mu.Lock() - for addr := range pool.queue { - // Skip local transactions from the eviction mechanism - if pool.locals.contains(addr) { - continue - } - // Any non-locals old enough should be removed - if time.Since(pool.beats[addr]) > pool.config.Lifetime { - list := pool.queue[addr].Flatten() - for _, tx := range list { - pool.removeTx(tx.Hash(), true) + // Track the previous and current head to feed to an idle reset + var ( + oldHead = head + newHead = oldHead + ) + // Consume chain head events and start resets when none is running + var ( + resetBusy = make(chan struct{}, 1) // Allow 1 reset to run concurrently + resetDone = make(chan *types.Header) + ) + var errc chan error + for errc == nil { + // Something interesting might have happened, run a reset if there is + // one needed but none is running. The resetter will run on its own + // goroutine to allow chain head events to be consumed contiguously. + if newHead != oldHead { + // Try to inject a busy marker and start a reset if successful + select { + case resetBusy <- struct{}{}: + // Busy marker injected, start a new subpool reset + go func(oldHead, newHead *types.Header) { + for _, subpool := range p.subpools { + subpool.Reset(oldHead, newHead) } - queuedEvictionMeter.Mark(int64(len(list))) - } - } - pool.mu.Unlock() + resetDone <- newHead + }(oldHead, newHead) - // Handle local transaction journal rotation - case <-journal.C: - if pool.journal != nil { - pool.mu.Lock() - if err := pool.journal.rotate(pool.local()); err != nil { - log.Warn("Failed to rotate local tx journal", "err", err) - } - pool.mu.Unlock() + default: + // Reset already running, wait until it finishes } } + // Wait for the next chain head event or a previous reset finish + select { + case event := <-newHeadCh: + // Chain moved forward, store the head for later consumption + newHead = event.Block.Header() + + case head := <-resetDone: + // Previous reset finished, update the old head and allow a new reset + oldHead = head + <-resetBusy + + case errc = <-p.quit: + // Termination requested, break out on the next loop round + } } + // Notify the closer of termination (no error possible for now) + errc <- nil } -// Stop terminates the transaction pool. -func (pool *TxPool) Stop() { - // Unsubscribe all subscriptions registered from txpool - pool.scope.Close() - - // Unsubscribe subscriptions registered from blockchain - pool.chainHeadSub.Unsubscribe() - pool.wg.Wait() - - if pool.journal != nil { - pool.journal.close() - } - log.Info("Transaction pool stopped") -} - -// SubscribeNewTxsEvent registers a subscription of NewTxsEvent and -// starts sending event to the given channel. -func (pool *TxPool) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription { - return pool.scope.Track(pool.txFeed.Subscribe(ch)) -} - -// GasPrice returns the current gas price enforced by the transaction pool. -func (pool *TxPool) GasPrice() *big.Int { - pool.mu.RLock() - defer pool.mu.RUnlock() - - return new(big.Int).Set(pool.gasPrice) -} - -// SetGasPrice updates the minimum price required by the transaction pool for a +// SetGasTip updates the minimum gas tip required by the transaction pool for a // new transaction, and drops all transactions below this threshold. -func (pool *TxPool) SetGasPrice(price *big.Int) { - pool.mu.Lock() - defer pool.mu.Unlock() +func (p *TxPool) SetGasTip(tip *big.Int) { + for _, subpool := range p.subpools { + subpool.SetGasTip(tip) + } +} - old := pool.gasPrice - pool.gasPrice = price - // if the min miner fee increased, remove transactions below the new threshold - if price.Cmp(old) > 0 { - // pool.priced is sorted by GasFeeCap, so we have to iterate through pool.all instead - drop := pool.all.RemotesBelowTip(price) - for _, tx := range drop { - pool.removeTx(tx.Hash(), false) +// Has returns an indicator whether the pool has a transaction cached with the +// given hash. +func (p *TxPool) Has(hash common.Hash) bool { + for _, subpool := range p.subpools { + if subpool.Has(hash) { + return true } - pool.priced.Removed(len(drop)) } - - log.Info("Transaction pool price threshold updated", "price", price) + return false } -// Nonce returns the next nonce of an account, with all transactions executable -// by the pool already applied on top. -func (pool *TxPool) Nonce(addr common.Address) uint64 { - pool.mu.RLock() - defer pool.mu.RUnlock() - - return pool.pendingNonces.get(addr) +// Get returns a transaction if it is contained in the pool, or nil otherwise. +func (p *TxPool) Get(hash common.Hash) *types.Transaction { + for _, subpool := range p.subpools { + if tx := subpool.Get(hash); tx != nil { + return tx + } + } + return nil } -// Stats retrieves the current pool stats, namely the number of pending and the -// number of queued (non-executable) transactions. -func (pool *TxPool) Stats() (int, int) { - pool.mu.RLock() - defer pool.mu.RUnlock() +// Add enqueues a batch of transactions into the pool if they are valid. Due +// to the large transaction churn, add may postpone fully integrating the tx +// to a later point to batch multiple ones together. +func (p *TxPool) Add(txs []*types.Transaction, local bool, sync bool) []error { + // Split the input transactions between the subpools. It shouldn't really + // happen that we receive merged batches, but better graceful than strange + // errors. + // + // We also need to track how the transactions were split across the subpools, + // so we can piece back the returned errors into the original order. + txsets := make([][]*types.Transaction, len(p.subpools)) + splits := make([]int, len(txs)) - return pool.stats() -} + for i, tx := range txs { + // Mark this transaction belonging to no-subpool + splits[i] = -1 -// stats retrieves the current pool stats, namely the number of pending and the -// number of queued (non-executable) transactions. -func (pool *TxPool) stats() (int, int) { - pending := 0 - for _, list := range pool.pending { - pending += list.Len() + // Try to find a subpool that accepts the transaction + for j, subpool := range p.subpools { + if subpool.Filter(tx) { + txsets[j] = append(txsets[j], tx) + splits[i] = j + break + } + } } - queued := 0 - for _, list := range pool.queue { - queued += list.Len() + // Add the transactions split apart to the individual subpools and piece + // back the errors into the original sort order. + errsets := make([][]error, len(p.subpools)) + for i := 0; i < len(p.subpools); i++ { + errsets[i] = p.subpools[i].Add(txsets[i], local, sync) } - return pending, queued -} - -// Content retrieves the data content of the transaction pool, returning all the -// pending as well as queued transactions, grouped by account and sorted by nonce. -func (pool *TxPool) Content() (map[common.Address]types.Transactions, map[common.Address]types.Transactions) { - pool.mu.Lock() - defer pool.mu.Unlock() - - pending := make(map[common.Address]types.Transactions, len(pool.pending)) - for addr, list := range pool.pending { - pending[addr] = list.Flatten() + errs := make([]error, len(txs)) + for i, split := range splits { + // If the transaction was rejected by all subpools, mark it unsupported + if split == -1 { + errs[i] = core.ErrTxTypeNotSupported + continue + } + // Find which subpool handled it and pull in the corresponding error + errs[i] = errsets[split][0] + errsets[split] = errsets[split][1:] } - queued := make(map[common.Address]types.Transactions, len(pool.queue)) - for addr, list := range pool.queue { - queued[addr] = list.Flatten() - } - return pending, queued -} - -// ContentFrom retrieves the data content of the transaction pool, returning the -// pending as well as queued transactions of this address, grouped by nonce. -func (pool *TxPool) ContentFrom(addr common.Address) (types.Transactions, types.Transactions) { - pool.mu.RLock() - defer pool.mu.RUnlock() - - var pending types.Transactions - if list, ok := pool.pending[addr]; ok { - pending = list.Flatten() - } - var queued types.Transactions - if list, ok := pool.queue[addr]; ok { - queued = list.Flatten() - } - return pending, queued + return errs } // Pending retrieves all currently processable transactions, grouped by origin -// account and sorted by nonce. The returned transaction set is a copy and can be -// freely modified by calling code. -// -// The enforceTips parameter can be used to do an extra filtering on the pending -// transactions and only return those whose **effective** tip is large enough in -// the next pending execution environment. -func (pool *TxPool) Pending(enforceTips bool) map[common.Address]types.Transactions { - pool.mu.Lock() - defer pool.mu.Unlock() - - pending := make(map[common.Address]types.Transactions, len(pool.pending)) - for addr, list := range pool.pending { - txs := list.Flatten() - - // If the miner requests tip enforcement, cap the lists now - if enforceTips && !pool.locals.contains(addr) { - for i, tx := range txs { - if tx.EffectiveGasTipIntCmp(pool.gasPrice, pool.priced.urgent.baseFee) < 0 { - txs = txs[:i] - break - } - } - } - if len(txs) > 0 { - pending[addr] = txs - } - } - return pending -} - -// Locals retrieves the accounts currently considered local by the pool. -func (pool *TxPool) Locals() []common.Address { - pool.mu.Lock() - defer pool.mu.Unlock() - - return pool.locals.flatten() -} - -// local retrieves all currently known local transactions, grouped by origin -// account and sorted by nonce. The returned transaction set is a copy and can be -// freely modified by calling code. -func (pool *TxPool) local() map[common.Address]types.Transactions { - txs := make(map[common.Address]types.Transactions) - for addr := range pool.locals.accounts { - if pending := pool.pending[addr]; pending != nil { - txs[addr] = append(txs[addr], pending.Flatten()...) - } - if queued := pool.queue[addr]; queued != nil { - txs[addr] = append(txs[addr], queued.Flatten()...) +// account and sorted by nonce. +func (p *TxPool) Pending(enforceTips bool) map[common.Address][]*LazyTransaction { + txs := make(map[common.Address][]*LazyTransaction) + for _, subpool := range p.subpools { + for addr, set := range subpool.Pending(enforceTips) { + txs[addr] = set } } return txs } -// validateTxBasics checks whether a transaction is valid according to the consensus -// rules, but does not check state-dependent validation such as sufficient balance. -// This check is meant as an early check which only needs to be performed once, -// and does not require the pool mutex to be held. -func (pool *TxPool) validateTxBasics(tx *types.Transaction, local bool) error { - // Accept only legacy transactions until EIP-2718/2930 activates. - if !pool.eip2718.Load() && tx.Type() != types.LegacyTxType { - return core.ErrTxTypeNotSupported +// SubscribeNewTxsEvent registers a subscription of NewTxsEvent and starts sending +// events to the given channel. +func (p *TxPool) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription { + subs := make([]event.Subscription, len(p.subpools)) + for i, subpool := range p.subpools { + subs[i] = subpool.SubscribeTransactions(ch) } - // Reject dynamic fee transactions until EIP-1559 activates. - if !pool.eip1559.Load() && tx.Type() == types.DynamicFeeTxType { - return core.ErrTxTypeNotSupported - } - // Reject blob transactions forever, those will have their own pool. - if tx.Type() == types.BlobTxType { - return core.ErrTxTypeNotSupported - } - // Reject transactions over defined size to prevent DOS attacks - if tx.Size() > txMaxSize { - return ErrOversizedData - } - // Check whether the init code size has been exceeded. - if pool.shanghai.Load() && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSize { - return fmt.Errorf("%w: code size %v limit %v", core.ErrMaxInitCodeSizeExceeded, len(tx.Data()), params.MaxInitCodeSize) - } - // Transactions can't be negative. This may never happen using RLP decoded - // transactions but may occur if you create a transaction using the RPC. - if tx.Value().Sign() < 0 { - return ErrNegativeValue - } - // Ensure the transaction doesn't exceed the current block limit gas. - if pool.currentMaxGas.Load() < tx.Gas() { - return ErrGasLimit - } - // Sanity check for extremely large numbers - if tx.GasFeeCap().BitLen() > 256 { - return core.ErrFeeCapVeryHigh - } - if tx.GasTipCap().BitLen() > 256 { - return core.ErrTipVeryHigh - } - // Ensure gasFeeCap is greater than or equal to gasTipCap. - if tx.GasFeeCapIntCmp(tx.GasTipCap()) < 0 { - return core.ErrTipAboveFeeCap - } - // Make sure the transaction is signed properly. - if _, err := types.Sender(pool.signer, tx); err != nil { - return ErrInvalidSender - } - // Drop non-local transactions under our own minimal accepted gas price or tip - if !local && tx.GasTipCapIntCmp(pool.gasPrice) < 0 { - return ErrUnderpriced - } - // Ensure the transaction has more gas than the basic tx fee. - intrGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, true, pool.istanbul.Load(), pool.shanghai.Load()) - if err != nil { - return err - } - if tx.Gas() < intrGas { - return core.ErrIntrinsicGas - } - return nil + return p.subs.Track(event.JoinSubscriptions(subs...)) } -// 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 (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { - // Signature has been checked already, this cannot error. - from, _ := types.Sender(pool.signer, tx) - // Ensure the transaction adheres to nonce ordering - if pool.currentState.GetNonce(from) > tx.Nonce() { - return core.ErrNonceTooLow - } - // Transactor should have enough funds to cover the costs - // cost == V + GP * GL - balance := pool.currentState.GetBalance(from) - if balance.Cmp(tx.Cost()) < 0 { - return core.ErrInsufficientFunds - } - - // Verify that replacing transactions will not result in overdraft - list := pool.pending[from] - if list != nil { // Sender already has pending txs - sum := new(big.Int).Add(tx.Cost(), list.totalcost) - if repl := list.txs.Get(tx.Nonce()); repl != nil { - // Deduct the cost of a transaction replaced by this - sum.Sub(sum, repl.Cost()) - } - if balance.Cmp(sum) < 0 { - log.Trace("Replacing transactions would overdraft", "sender", from, "balance", pool.currentState.GetBalance(from), "required", sum) - return ErrOverdraft +// Nonce returns the next nonce of an account, with all transactions executable +// by the pool already applied on top. +func (p *TxPool) Nonce(addr common.Address) uint64 { + // Since (for now) accounts are unique to subpools, only one pool will have + // (at max) a non-state nonce. To avoid stateful lookups, just return the + // highest nonce for now. + var nonce uint64 + for _, subpool := range p.subpools { + if next := subpool.Nonce(addr); nonce < next { + nonce = next } } - return nil + return nonce } -// add validates a transaction and inserts it into the non-executable queue for later -// pending promotion and execution. If the transaction is a replacement for an already -// pending or queued one, it overwrites the previous transaction if its price is higher. -// -// If a newly added transaction is marked as local, its sending account will be -// be added to the allowlist, preventing any associated transaction from being dropped -// out of the pool due to pricing constraints. -func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err error) { - // If the transaction is already known, discard it - hash := tx.Hash() - if pool.all.Get(hash) != nil { - log.Trace("Discarding already known transaction", "hash", hash) - knownTxMeter.Mark(1) - return false, ErrAlreadyKnown +// Stats retrieves the current pool stats, namely the number of pending and the +// number of queued (non-executable) transactions. +func (p *TxPool) Stats() (int, int) { + var runnable, blocked int + for _, subpool := range p.subpools { + run, block := subpool.Stats() + + runnable += run + blocked += block } - // Make the local flag. If it's from local source or it's from the network but - // the sender is marked as local previously, treat it as the local transaction. - isLocal := local || pool.locals.containsTx(tx) - - // If the transaction fails basic validation, discard it - if err := pool.validateTx(tx, isLocal); err != nil { - log.Trace("Discarding invalid transaction", "hash", hash, "err", err) - invalidTxMeter.Mark(1) - return false, err - } - - // already validated by this point - from, _ := types.Sender(pool.signer, tx) - - // If the transaction pool is full, discard underpriced transactions - if uint64(pool.all.Slots()+numSlots(tx)) > pool.config.GlobalSlots+pool.config.GlobalQueue { - // If the new transaction is underpriced, don't accept it - if !isLocal && pool.priced.Underpriced(tx) { - log.Trace("Discarding underpriced transaction", "hash", hash, "gasTipCap", tx.GasTipCap(), "gasFeeCap", tx.GasFeeCap()) - underpricedTxMeter.Mark(1) - return false, ErrUnderpriced - } - - // We're about to replace a transaction. The reorg does a more thorough - // analysis of what to remove and how, but it runs async. We don't want to - // do too many replacements between reorg-runs, so we cap the number of - // replacements to 25% of the slots - if pool.changesSinceReorg > int(pool.config.GlobalSlots/4) { - throttleTxMeter.Mark(1) - return false, ErrTxPoolOverflow - } - - // New transaction is better than our worse ones, make room for it. - // If it's a local transaction, forcibly discard all available transactions. - // Otherwise if we can't make enough room for new one, abort the operation. - drop, success := pool.priced.Discard(pool.all.Slots()-int(pool.config.GlobalSlots+pool.config.GlobalQueue)+numSlots(tx), isLocal) - - // Special case, we still can't make the room for the new remote one. - if !isLocal && !success { - log.Trace("Discarding overflown transaction", "hash", hash) - overflowedTxMeter.Mark(1) - return false, ErrTxPoolOverflow - } - - // If the new transaction is a future transaction it should never churn pending transactions - if !isLocal && pool.isGapped(from, tx) { - var replacesPending bool - for _, dropTx := range drop { - dropSender, _ := types.Sender(pool.signer, dropTx) - if list := pool.pending[dropSender]; list != nil && list.Contains(dropTx.Nonce()) { - replacesPending = true - break - } - } - // Add all transactions back to the priced queue - if replacesPending { - for _, dropTx := range drop { - pool.priced.Put(dropTx, false) - } - log.Trace("Discarding future transaction replacing pending tx", "hash", hash) - return false, ErrFutureReplacePending - } - } - - // Kick out the underpriced remote transactions. - for _, tx := range drop { - log.Trace("Discarding freshly underpriced transaction", "hash", tx.Hash(), "gasTipCap", tx.GasTipCap(), "gasFeeCap", tx.GasFeeCap()) - underpricedTxMeter.Mark(1) - dropped := pool.removeTx(tx.Hash(), false) - pool.changesSinceReorg += dropped - } - } - - // Try to replace an existing transaction in the pending pool - if list := pool.pending[from]; list != nil && list.Contains(tx.Nonce()) { - // Nonce already pending, check if required price bump is met - inserted, old := list.Add(tx, pool.config.PriceBump) - if !inserted { - pendingDiscardMeter.Mark(1) - return false, ErrReplaceUnderpriced - } - // New transaction is better, replace old one - if old != nil { - pool.all.Remove(old.Hash()) - pool.priced.Removed(1) - pendingReplaceMeter.Mark(1) - } - pool.all.Add(tx, isLocal) - pool.priced.Put(tx, isLocal) - pool.journalTx(from, tx) - pool.queueTxEvent(tx) - log.Trace("Pooled new executable transaction", "hash", hash, "from", from, "to", tx.To()) - - // Successful promotion, bump the heartbeat - pool.beats[from] = time.Now() - return old != nil, nil - } - // New transaction isn't replacing a pending one, push into queue - replaced, err = pool.enqueueTx(hash, tx, isLocal, true) - if err != nil { - return false, err - } - // Mark local addresses and journal local transactions - if local && !pool.locals.contains(from) { - log.Info("Setting new local account", "address", from) - pool.locals.add(from) - pool.priced.Removed(pool.all.RemoteToLocals(pool.locals)) // Migrate the remotes if it's marked as local first time. - } - if isLocal { - localGauge.Inc(1) - } - pool.journalTx(from, tx) - - log.Trace("Pooled new future transaction", "hash", hash, "from", from, "to", tx.To()) - return replaced, nil + return runnable, blocked } -// isGapped reports whether the given transaction is immediately executable. -func (pool *TxPool) isGapped(from common.Address, tx *types.Transaction) bool { - // Short circuit if transaction matches pending nonce and can be promoted - // to pending list as an executable transaction. - next := pool.pendingNonces.get(from) - if tx.Nonce() == next { - return false - } - // The transaction has a nonce gap with pending list, it's only considered - // as executable if transactions in queue can fill up the nonce gap. - queue, ok := pool.queue[from] - if !ok { - return true - } - for nonce := next; nonce < tx.Nonce(); nonce++ { - if !queue.Contains(nonce) { - return true // txs in queue can't fill up the nonce gap - } - } - return false -} - -// enqueueTx inserts a new transaction into the non-executable transaction queue. -// -// Note, this method assumes the pool lock is held! -func (pool *TxPool) enqueueTx(hash common.Hash, tx *types.Transaction, local bool, addAll bool) (bool, error) { - // Try to insert the transaction into the future queue - from, _ := types.Sender(pool.signer, tx) // already validated - if pool.queue[from] == nil { - pool.queue[from] = newList(false) - } - inserted, old := pool.queue[from].Add(tx, pool.config.PriceBump) - if !inserted { - // An older transaction was better, discard this - queuedDiscardMeter.Mark(1) - return false, ErrReplaceUnderpriced - } - // Discard any previous transaction and mark this - if old != nil { - pool.all.Remove(old.Hash()) - pool.priced.Removed(1) - queuedReplaceMeter.Mark(1) - } else { - // Nothing was replaced, bump the queued counter - queuedGauge.Inc(1) - } - // If the transaction isn't in lookup set but it's expected to be there, - // show the error log. - if pool.all.Get(hash) == nil && !addAll { - log.Error("Missing transaction in lookup set, please report the issue", "hash", hash) - } - if addAll { - pool.all.Add(tx, local) - pool.priced.Put(tx, local) - } - // If we never record the heartbeat, do it right now. - if _, exist := pool.beats[from]; !exist { - pool.beats[from] = time.Now() - } - return old != nil, nil -} - -// journalTx adds the specified transaction to the local disk journal if it is -// deemed to have been sent from a local account. -func (pool *TxPool) journalTx(from common.Address, tx *types.Transaction) { - // Only journal if it's enabled and the transaction is local - if pool.journal == nil || !pool.locals.contains(from) { - return - } - if err := pool.journal.insert(tx); err != nil { - log.Warn("Failed to journal local transaction", "err", err) - } -} - -// promoteTx adds a transaction to the pending (processable) list of transactions -// and returns whether it was inserted or an older was better. -// -// Note, this method assumes the pool lock is held! -func (pool *TxPool) promoteTx(addr common.Address, hash common.Hash, tx *types.Transaction) bool { - // Try to insert the transaction into the pending queue - if pool.pending[addr] == nil { - pool.pending[addr] = newList(true) - } - list := pool.pending[addr] - - inserted, old := list.Add(tx, pool.config.PriceBump) - if !inserted { - // An older transaction was better, discard this - pool.all.Remove(hash) - pool.priced.Removed(1) - pendingDiscardMeter.Mark(1) - return false - } - // Otherwise discard any previous transaction and mark this - if old != nil { - pool.all.Remove(old.Hash()) - pool.priced.Removed(1) - pendingReplaceMeter.Mark(1) - } else { - // Nothing was replaced, bump the pending counter - pendingGauge.Inc(1) - } - // Set the potentially new pending nonce and notify any subsystems of the new tx - pool.pendingNonces.set(addr, tx.Nonce()+1) - - // Successful promotion, bump the heartbeat - pool.beats[addr] = time.Now() - return true -} - -// AddLocals enqueues a batch of transactions into the pool if they are valid, marking the -// senders as a local ones, ensuring they go around the local pricing constraints. -// -// This method is used to add transactions from the RPC API and performs synchronous pool -// reorganization and event propagation. -func (pool *TxPool) AddLocals(txs []*types.Transaction) []error { - return pool.addTxs(txs, !pool.config.NoLocals, true) -} - -// AddLocal enqueues a single local transaction into the pool if it is valid. This is -// a convenience wrapper around AddLocals. -func (pool *TxPool) AddLocal(tx *types.Transaction) error { - errs := pool.AddLocals([]*types.Transaction{tx}) - return errs[0] -} - -// AddRemotes enqueues a batch of transactions into the pool if they are valid. If the -// senders are not among the locally tracked ones, full pricing constraints will apply. -// -// This method is used to add transactions from the p2p network and does not wait for pool -// reorganization and internal event propagation. -func (pool *TxPool) AddRemotes(txs []*types.Transaction) []error { - return pool.addTxs(txs, false, false) -} - -// AddRemotesSync is like AddRemotes, but waits for pool reorganization. Tests use this method. -func (pool *TxPool) AddRemotesSync(txs []*types.Transaction) []error { - return pool.addTxs(txs, false, true) -} - -// This is like AddRemotes with a single transaction, but waits for pool reorganization. Tests use this method. -func (pool *TxPool) addRemoteSync(tx *types.Transaction) error { - errs := pool.AddRemotesSync([]*types.Transaction{tx}) - return errs[0] -} - -// AddRemote enqueues a single transaction into the pool if it is valid. This is a convenience -// wrapper around AddRemotes. -// -// Deprecated: use AddRemotes -func (pool *TxPool) AddRemote(tx *types.Transaction) error { - errs := pool.AddRemotes([]*types.Transaction{tx}) - return errs[0] -} - -// addTxs attempts to queue a batch of transactions if they are valid. -func (pool *TxPool) addTxs(txs []*types.Transaction, local, sync bool) []error { - // Filter out known ones without obtaining the pool lock or recovering signatures +// Content retrieves the data content of the transaction pool, returning all the +// pending as well as queued transactions, grouped by account and sorted by nonce. +func (p *TxPool) Content() (map[common.Address][]*types.Transaction, map[common.Address][]*types.Transaction) { var ( - errs = make([]error, len(txs)) - news = make([]*types.Transaction, 0, len(txs)) + runnable = make(map[common.Address][]*types.Transaction) + blocked = make(map[common.Address][]*types.Transaction) ) - for i, tx := range txs { - // If the transaction is known, pre-set the error slot - if pool.all.Get(tx.Hash()) != nil { - errs[i] = ErrAlreadyKnown - knownTxMeter.Mark(1) - continue - } - // Exclude transactions with basic errors, e.g invalid signatures and - // insufficient intrinsic gas as soon as possible and cache senders - // in transactions before obtaining lock + for _, subpool := range p.subpools { + run, block := subpool.Content() - if err := pool.validateTxBasics(tx, local); err != nil { - errs[i] = err - invalidTxMeter.Mark(1) - continue + for addr, txs := range run { + runnable[addr] = txs } - // Accumulate all unknown transactions for deeper processing - news = append(news, tx) - } - if len(news) == 0 { - return errs - } - - // Process all the new transaction and merge any errors into the original slice - pool.mu.Lock() - newErrs, dirtyAddrs := pool.addTxsLocked(news, local) - pool.mu.Unlock() - - var nilSlot = 0 - for _, err := range newErrs { - for errs[nilSlot] != nil { - nilSlot++ + for addr, txs := range block { + blocked[addr] = txs } - errs[nilSlot] = err - nilSlot++ } - // Reorg the pool internals if needed and return - done := pool.requestPromoteExecutables(dirtyAddrs) - if sync { - <-done - } - return errs + return runnable, blocked } -// addTxsLocked attempts to queue a batch of transactions if they are valid. -// The transaction pool lock must be held. -func (pool *TxPool) addTxsLocked(txs []*types.Transaction, local bool) ([]error, *accountSet) { - dirty := newAccountSet(pool.signer) - errs := make([]error, len(txs)) - for i, tx := range txs { - replaced, err := pool.add(tx, local) - errs[i] = err - if err == nil && !replaced { - dirty.addTx(tx) +// ContentFrom retrieves the data content of the transaction pool, returning the +// pending as well as queued transactions of this address, grouped by nonce. +func (p *TxPool) ContentFrom(addr common.Address) ([]*types.Transaction, []*types.Transaction) { + for _, subpool := range p.subpools { + run, block := subpool.ContentFrom(addr) + if len(run) != 0 || len(block) != 0 { + return run, block } } - validTxMeter.Mark(int64(len(dirty.accounts))) - return errs, dirty + return []*types.Transaction{}, []*types.Transaction{} } -// Status returns the status (unknown/pending/queued) of a batch of transactions +// Locals retrieves the accounts currently considered local by the pool. +func (p *TxPool) Locals() []common.Address { + // Retrieve the locals from each subpool and deduplicate them + locals := make(map[common.Address]struct{}) + for _, subpool := range p.subpools { + for _, local := range subpool.Locals() { + locals[local] = struct{}{} + } + } + // Flatten and return the deduplicated local set + flat := make([]common.Address, 0, len(locals)) + for local := range locals { + flat = append(flat, local) + } + return flat +} + +// Status returns the known status (unknown/pending/queued) of a transaction // identified by their hashes. -func (pool *TxPool) Status(hashes []common.Hash) []TxStatus { - status := make([]TxStatus, len(hashes)) - for i, hash := range hashes { - tx := pool.Get(hash) - if tx == nil { - continue - } - from, _ := types.Sender(pool.signer, tx) // already validated - pool.mu.RLock() - if txList := pool.pending[from]; txList != nil && txList.txs.items[tx.Nonce()] != nil { - status[i] = TxStatusPending - } else if txList := pool.queue[from]; txList != nil && txList.txs.items[tx.Nonce()] != nil { - status[i] = TxStatusQueued - } - // implicit else: the tx may have been included into a block between - // checking pool.Get and obtaining the lock. In that case, TxStatusUnknown is correct - pool.mu.RUnlock() - } - return status -} - -// Get returns a transaction if it is contained in the pool and nil otherwise. -func (pool *TxPool) Get(hash common.Hash) *types.Transaction { - return pool.all.Get(hash) -} - -// Has returns an indicator whether txpool has a transaction cached with the -// given hash. -func (pool *TxPool) Has(hash common.Hash) bool { - return pool.all.Get(hash) != nil -} - -// removeTx removes a single transaction from the queue, moving all subsequent -// transactions back to the future queue. -// Returns the number of transactions removed from the pending queue. -func (pool *TxPool) removeTx(hash common.Hash, outofbound bool) int { - // Fetch the transaction we wish to delete - tx := pool.all.Get(hash) - if tx == nil { - return 0 - } - addr, _ := types.Sender(pool.signer, tx) // already validated during insertion - - // Remove it from the list of known transactions - pool.all.Remove(hash) - if outofbound { - pool.priced.Removed(1) - } - if pool.locals.contains(addr) { - localGauge.Dec(1) - } - // Remove the transaction from the pending lists and reset the account nonce - if pending := pool.pending[addr]; pending != nil { - if removed, invalids := pending.Remove(tx); removed { - // If no more pending transactions are left, remove the list - if pending.Empty() { - delete(pool.pending, addr) - } - // Postpone any invalidated transactions - for _, tx := range invalids { - // Internal shuffle shouldn't touch the lookup set. - pool.enqueueTx(tx.Hash(), tx, false, false) - } - // Update the account nonce if needed - pool.pendingNonces.setIfLower(addr, tx.Nonce()) - // Reduce the pending counter - pendingGauge.Dec(int64(1 + len(invalids))) - return 1 + len(invalids) +func (p *TxPool) Status(hash common.Hash) TxStatus { + for _, subpool := range p.subpools { + if status := subpool.Status(hash); status != TxStatusUnknown { + return status } } - // Transaction is in the future queue - if future := pool.queue[addr]; future != nil { - if removed, _ := future.Remove(tx); removed { - // Reduce the queued counter - queuedGauge.Dec(1) - } - if future.Empty() { - delete(pool.queue, addr) - delete(pool.beats, addr) - } - } - return 0 -} - -// requestReset requests a pool reset to the new head block. -// The returned channel is closed when the reset has occurred. -func (pool *TxPool) requestReset(oldHead *types.Header, newHead *types.Header) chan struct{} { - select { - case pool.reqResetCh <- &txpoolResetRequest{oldHead, newHead}: - return <-pool.reorgDoneCh - case <-pool.reorgShutdownCh: - return pool.reorgShutdownCh - } -} - -// requestPromoteExecutables requests transaction promotion checks for the given addresses. -// The returned channel is closed when the promotion checks have occurred. -func (pool *TxPool) requestPromoteExecutables(set *accountSet) chan struct{} { - select { - case pool.reqPromoteCh <- set: - return <-pool.reorgDoneCh - case <-pool.reorgShutdownCh: - return pool.reorgShutdownCh - } -} - -// queueTxEvent enqueues a transaction event to be sent in the next reorg run. -func (pool *TxPool) queueTxEvent(tx *types.Transaction) { - select { - case pool.queueTxEventCh <- tx: - case <-pool.reorgShutdownCh: - } -} - -// scheduleReorgLoop schedules runs of reset and promoteExecutables. Code above should not -// call those methods directly, but request them being run using requestReset and -// requestPromoteExecutables instead. -func (pool *TxPool) scheduleReorgLoop() { - defer pool.wg.Done() - - var ( - curDone chan struct{} // non-nil while runReorg is active - nextDone = make(chan struct{}) - launchNextRun bool - reset *txpoolResetRequest - dirtyAccounts *accountSet - queuedEvents = make(map[common.Address]*sortedMap) - ) - for { - // Launch next background reorg if needed - if curDone == nil && launchNextRun { - // Run the background reorg and announcements - go pool.runReorg(nextDone, reset, dirtyAccounts, queuedEvents) - - // Prepare everything for the next round of reorg - curDone, nextDone = nextDone, make(chan struct{}) - launchNextRun = false - - reset, dirtyAccounts = nil, nil - queuedEvents = make(map[common.Address]*sortedMap) - } - - select { - case req := <-pool.reqResetCh: - // Reset request: update head if request is already pending. - if reset == nil { - reset = req - } else { - reset.newHead = req.newHead - } - launchNextRun = true - pool.reorgDoneCh <- nextDone - - case req := <-pool.reqPromoteCh: - // Promote request: update address set if request is already pending. - if dirtyAccounts == nil { - dirtyAccounts = req - } else { - dirtyAccounts.merge(req) - } - launchNextRun = true - pool.reorgDoneCh <- nextDone - - case tx := <-pool.queueTxEventCh: - // Queue up the event, but don't schedule a reorg. It's up to the caller to - // request one later if they want the events sent. - addr, _ := types.Sender(pool.signer, tx) - if _, ok := queuedEvents[addr]; !ok { - queuedEvents[addr] = newSortedMap() - } - queuedEvents[addr].Put(tx) - - case <-curDone: - curDone = nil - - case <-pool.reorgShutdownCh: - // Wait for current run to finish. - if curDone != nil { - <-curDone - } - close(nextDone) - return - } - } -} - -// runReorg runs reset and promoteExecutables on behalf of scheduleReorgLoop. -func (pool *TxPool) runReorg(done chan struct{}, reset *txpoolResetRequest, dirtyAccounts *accountSet, events map[common.Address]*sortedMap) { - defer func(t0 time.Time) { - reorgDurationTimer.Update(time.Since(t0)) - }(time.Now()) - defer close(done) - - var promoteAddrs []common.Address - if dirtyAccounts != nil && reset == nil { - // Only dirty accounts need to be promoted, unless we're resetting. - // For resets, all addresses in the tx queue will be promoted and - // the flatten operation can be avoided. - promoteAddrs = dirtyAccounts.flatten() - } - pool.mu.Lock() - if reset != nil { - // Reset from the old head to the new, rescheduling any reorged transactions - pool.reset(reset.oldHead, reset.newHead) - - // Nonces were reset, discard any events that became stale - for addr := range events { - events[addr].Forward(pool.pendingNonces.get(addr)) - if events[addr].Len() == 0 { - delete(events, addr) - } - } - // Reset needs promote for all addresses - promoteAddrs = make([]common.Address, 0, len(pool.queue)) - for addr := range pool.queue { - promoteAddrs = append(promoteAddrs, addr) - } - } - // Check for pending transactions for every account that sent new ones - promoted := pool.promoteExecutables(promoteAddrs) - - // If a new block appeared, validate the pool of pending transactions. This will - // remove any transaction that has been included in the block or was invalidated - // because of another transaction (e.g. higher gas price). - if reset != nil { - pool.demoteUnexecutables() - if reset.newHead != nil && pool.chainconfig.IsLondon(new(big.Int).Add(reset.newHead.Number, big.NewInt(1))) { - pendingBaseFee := misc.CalcBaseFee(pool.chainconfig, reset.newHead) - pool.priced.SetBaseFee(pendingBaseFee) - } - // Update all accounts to the latest known pending nonce - nonces := make(map[common.Address]uint64, len(pool.pending)) - for addr, list := range pool.pending { - highestPending := list.LastElement() - nonces[addr] = highestPending.Nonce() + 1 - } - pool.pendingNonces.setAll(nonces) - } - // Ensure pool.queue and pool.pending sizes stay within the configured limits. - pool.truncatePending() - pool.truncateQueue() - - dropBetweenReorgHistogram.Update(int64(pool.changesSinceReorg)) - pool.changesSinceReorg = 0 // Reset change counter - pool.mu.Unlock() - - // Notify subsystems for newly added transactions - for _, tx := range promoted { - addr, _ := types.Sender(pool.signer, tx) - if _, ok := events[addr]; !ok { - events[addr] = newSortedMap() - } - events[addr].Put(tx) - } - if len(events) > 0 { - var txs []*types.Transaction - for _, set := range events { - txs = append(txs, set.Flatten()...) - } - pool.txFeed.Send(core.NewTxsEvent{Txs: txs}) - } -} - -// reset retrieves the current state of the blockchain and ensures the content -// of the transaction pool is valid with regard to the chain state. -func (pool *TxPool) reset(oldHead, newHead *types.Header) { - // If we're reorging an old state, reinject all dropped transactions - var reinject types.Transactions - - if oldHead != nil && oldHead.Hash() != newHead.ParentHash { - // If the reorg is too deep, avoid doing it (will happen during fast sync) - oldNum := oldHead.Number.Uint64() - newNum := newHead.Number.Uint64() - - if depth := uint64(math.Abs(float64(oldNum) - float64(newNum))); depth > 64 { - log.Debug("Skipping deep transaction reorg", "depth", depth) - } else { - // Reorg seems shallow enough to pull in all transactions into memory - var discarded, included types.Transactions - var ( - rem = pool.chain.GetBlock(oldHead.Hash(), oldHead.Number.Uint64()) - add = pool.chain.GetBlock(newHead.Hash(), newHead.Number.Uint64()) - ) - if rem == nil { - // This can happen if a setHead is performed, where we simply discard the old - // head from the chain. - // If that is the case, we don't have the lost transactions anymore, and - // there's nothing to add - if newNum >= oldNum { - // If we reorged to a same or higher number, then it's not a case of setHead - log.Warn("Transaction pool reset with missing oldhead", - "old", oldHead.Hash(), "oldnum", oldNum, "new", newHead.Hash(), "newnum", newNum) - return - } - // If the reorg ended up on a lower number, it's indicative of setHead being the cause - log.Debug("Skipping transaction reset caused by setHead", - "old", oldHead.Hash(), "oldnum", oldNum, "new", newHead.Hash(), "newnum", newNum) - // We still need to update the current state s.th. the lost transactions can be readded by the user - } else { - for rem.NumberU64() > add.NumberU64() { - discarded = append(discarded, rem.Transactions()...) - if rem = pool.chain.GetBlock(rem.ParentHash(), rem.NumberU64()-1); rem == nil { - log.Error("Unrooted old chain seen by tx pool", "block", oldHead.Number, "hash", oldHead.Hash()) - return - } - } - for add.NumberU64() > rem.NumberU64() { - included = append(included, add.Transactions()...) - if add = pool.chain.GetBlock(add.ParentHash(), add.NumberU64()-1); add == nil { - log.Error("Unrooted new chain seen by tx pool", "block", newHead.Number, "hash", newHead.Hash()) - return - } - } - for rem.Hash() != add.Hash() { - discarded = append(discarded, rem.Transactions()...) - if rem = pool.chain.GetBlock(rem.ParentHash(), rem.NumberU64()-1); rem == nil { - log.Error("Unrooted old chain seen by tx pool", "block", oldHead.Number, "hash", oldHead.Hash()) - return - } - included = append(included, add.Transactions()...) - if add = pool.chain.GetBlock(add.ParentHash(), add.NumberU64()-1); add == nil { - log.Error("Unrooted new chain seen by tx pool", "block", newHead.Number, "hash", newHead.Hash()) - return - } - } - reinject = types.TxDifference(discarded, included) - } - } - } - // Initialize the internal state to the current head - if newHead == nil { - newHead = pool.chain.CurrentBlock() // Special case during testing - } - statedb, err := pool.chain.StateAt(newHead.Root) - if err != nil { - log.Error("Failed to reset txpool state", "err", err) - return - } - pool.currentState = statedb - pool.pendingNonces = newNoncer(statedb) - pool.currentMaxGas.Store(newHead.GasLimit) - - // Inject any transactions discarded due to reorgs - log.Debug("Reinjecting stale transactions", "count", len(reinject)) - core.SenderCacher.Recover(pool.signer, reinject) - pool.addTxsLocked(reinject, false) - - // Update all fork indicator by next pending block number. - next := new(big.Int).Add(newHead.Number, big.NewInt(1)) - pool.istanbul.Store(pool.chainconfig.IsIstanbul(next)) - pool.eip2718.Store(pool.chainconfig.IsBerlin(next)) - pool.eip1559.Store(pool.chainconfig.IsLondon(next)) - pool.shanghai.Store(pool.chainconfig.IsShanghai(uint64(time.Now().Unix()))) -} - -// promoteExecutables moves transactions that have become processable from the -// future queue to the set of pending transactions. During this process, all -// invalidated transactions (low nonce, low balance) are deleted. -func (pool *TxPool) promoteExecutables(accounts []common.Address) []*types.Transaction { - // Track the promoted transactions to broadcast them at once - var promoted []*types.Transaction - - // Iterate over all accounts and promote any executable transactions - for _, addr := range accounts { - list := pool.queue[addr] - if list == nil { - continue // Just in case someone calls with a non existing account - } - // Drop all transactions that are deemed too old (low nonce) - forwards := list.Forward(pool.currentState.GetNonce(addr)) - for _, tx := range forwards { - hash := tx.Hash() - pool.all.Remove(hash) - } - log.Trace("Removed old queued transactions", "count", len(forwards)) - // Drop all transactions that are too costly (low balance or out of gas) - drops, _ := list.Filter(pool.currentState.GetBalance(addr), pool.currentMaxGas.Load()) - for _, tx := range drops { - hash := tx.Hash() - pool.all.Remove(hash) - } - log.Trace("Removed unpayable queued transactions", "count", len(drops)) - queuedNofundsMeter.Mark(int64(len(drops))) - - // Gather all executable transactions and promote them - readies := list.Ready(pool.pendingNonces.get(addr)) - for _, tx := range readies { - hash := tx.Hash() - if pool.promoteTx(addr, hash, tx) { - promoted = append(promoted, tx) - } - } - log.Trace("Promoted queued transactions", "count", len(promoted)) - queuedGauge.Dec(int64(len(readies))) - - // Drop all transactions over the allowed limit - var caps types.Transactions - if !pool.locals.contains(addr) { - caps = list.Cap(int(pool.config.AccountQueue)) - for _, tx := range caps { - hash := tx.Hash() - pool.all.Remove(hash) - log.Trace("Removed cap-exceeding queued transaction", "hash", hash) - } - queuedRateLimitMeter.Mark(int64(len(caps))) - } - // Mark all the items dropped as removed - pool.priced.Removed(len(forwards) + len(drops) + len(caps)) - queuedGauge.Dec(int64(len(forwards) + len(drops) + len(caps))) - if pool.locals.contains(addr) { - localGauge.Dec(int64(len(forwards) + len(drops) + len(caps))) - } - // Delete the entire queue entry if it became empty. - if list.Empty() { - delete(pool.queue, addr) - delete(pool.beats, addr) - } - } - return promoted -} - -// truncatePending removes transactions from the pending queue if the pool is above the -// pending limit. The algorithm tries to reduce transaction counts by an approximately -// equal number for all for accounts with many pending transactions. -func (pool *TxPool) truncatePending() { - pending := uint64(0) - for _, list := range pool.pending { - pending += uint64(list.Len()) - } - if pending <= pool.config.GlobalSlots { - return - } - - pendingBeforeCap := pending - // Assemble a spam order to penalize large transactors first - spammers := prque.New[int64, common.Address](nil) - for addr, list := range pool.pending { - // Only evict transactions from high rollers - if !pool.locals.contains(addr) && uint64(list.Len()) > pool.config.AccountSlots { - spammers.Push(addr, int64(list.Len())) - } - } - // Gradually drop transactions from offenders - offenders := []common.Address{} - for pending > pool.config.GlobalSlots && !spammers.Empty() { - // Retrieve the next offender if not local address - offender, _ := spammers.Pop() - offenders = append(offenders, offender) - - // Equalize balances until all the same or below threshold - if len(offenders) > 1 { - // Calculate the equalization threshold for all current offenders - threshold := pool.pending[offender].Len() - - // Iteratively reduce all offenders until below limit or threshold reached - for pending > pool.config.GlobalSlots && pool.pending[offenders[len(offenders)-2]].Len() > threshold { - for i := 0; i < len(offenders)-1; i++ { - list := pool.pending[offenders[i]] - - caps := list.Cap(list.Len() - 1) - for _, tx := range caps { - // Drop the transaction from the global pools too - hash := tx.Hash() - pool.all.Remove(hash) - - // Update the account nonce to the dropped transaction - pool.pendingNonces.setIfLower(offenders[i], tx.Nonce()) - log.Trace("Removed fairness-exceeding pending transaction", "hash", hash) - } - pool.priced.Removed(len(caps)) - pendingGauge.Dec(int64(len(caps))) - if pool.locals.contains(offenders[i]) { - localGauge.Dec(int64(len(caps))) - } - pending-- - } - } - } - } - - // If still above threshold, reduce to limit or min allowance - if pending > pool.config.GlobalSlots && len(offenders) > 0 { - for pending > pool.config.GlobalSlots && uint64(pool.pending[offenders[len(offenders)-1]].Len()) > pool.config.AccountSlots { - for _, addr := range offenders { - list := pool.pending[addr] - - caps := list.Cap(list.Len() - 1) - for _, tx := range caps { - // Drop the transaction from the global pools too - hash := tx.Hash() - pool.all.Remove(hash) - - // Update the account nonce to the dropped transaction - pool.pendingNonces.setIfLower(addr, tx.Nonce()) - log.Trace("Removed fairness-exceeding pending transaction", "hash", hash) - } - pool.priced.Removed(len(caps)) - pendingGauge.Dec(int64(len(caps))) - if pool.locals.contains(addr) { - localGauge.Dec(int64(len(caps))) - } - pending-- - } - } - } - pendingRateLimitMeter.Mark(int64(pendingBeforeCap - pending)) -} - -// truncateQueue drops the oldest transactions in the queue if the pool is above the global queue limit. -func (pool *TxPool) truncateQueue() { - queued := uint64(0) - for _, list := range pool.queue { - queued += uint64(list.Len()) - } - if queued <= pool.config.GlobalQueue { - return - } - - // Sort all accounts with queued transactions by heartbeat - addresses := make(addressesByHeartbeat, 0, len(pool.queue)) - for addr := range pool.queue { - if !pool.locals.contains(addr) { // don't drop locals - addresses = append(addresses, addressByHeartbeat{addr, pool.beats[addr]}) - } - } - sort.Sort(sort.Reverse(addresses)) - - // Drop transactions until the total is below the limit or only locals remain - for drop := queued - pool.config.GlobalQueue; drop > 0 && len(addresses) > 0; { - addr := addresses[len(addresses)-1] - list := pool.queue[addr.address] - - addresses = addresses[:len(addresses)-1] - - // Drop all transactions if they are less than the overflow - if size := uint64(list.Len()); size <= drop { - for _, tx := range list.Flatten() { - pool.removeTx(tx.Hash(), true) - } - drop -= size - queuedRateLimitMeter.Mark(int64(size)) - continue - } - // Otherwise drop only last few transactions - txs := list.Flatten() - for i := len(txs) - 1; i >= 0 && drop > 0; i-- { - pool.removeTx(txs[i].Hash(), true) - drop-- - queuedRateLimitMeter.Mark(1) - } - } -} - -// demoteUnexecutables removes invalid and processed transactions from the pools -// executable/pending queue and any subsequent transactions that become unexecutable -// are moved back into the future queue. -// -// Note: transactions are not marked as removed in the priced list because re-heaping -// is always explicitly triggered by SetBaseFee and it would be unnecessary and wasteful -// to trigger a re-heap is this function -func (pool *TxPool) demoteUnexecutables() { - // Iterate over all accounts and demote any non-executable transactions - for addr, list := range pool.pending { - nonce := pool.currentState.GetNonce(addr) - - // Drop all transactions that are deemed too old (low nonce) - olds := list.Forward(nonce) - for _, tx := range olds { - hash := tx.Hash() - pool.all.Remove(hash) - log.Trace("Removed old pending transaction", "hash", hash) - } - // Drop all transactions that are too costly (low balance or out of gas), and queue any invalids back for later - drops, invalids := list.Filter(pool.currentState.GetBalance(addr), pool.currentMaxGas.Load()) - for _, tx := range drops { - hash := tx.Hash() - log.Trace("Removed unpayable pending transaction", "hash", hash) - pool.all.Remove(hash) - } - pendingNofundsMeter.Mark(int64(len(drops))) - - for _, tx := range invalids { - hash := tx.Hash() - log.Trace("Demoting pending transaction", "hash", hash) - - // Internal shuffle shouldn't touch the lookup set. - pool.enqueueTx(hash, tx, false, false) - } - pendingGauge.Dec(int64(len(olds) + len(drops) + len(invalids))) - if pool.locals.contains(addr) { - localGauge.Dec(int64(len(olds) + len(drops) + len(invalids))) - } - // If there's a gap in front, alert (should never happen) and postpone all transactions - if list.Len() > 0 && list.txs.Get(nonce) == nil { - gapped := list.Cap(0) - for _, tx := range gapped { - hash := tx.Hash() - log.Error("Demoting invalidated transaction", "hash", hash) - - // Internal shuffle shouldn't touch the lookup set. - pool.enqueueTx(hash, tx, false, false) - } - pendingGauge.Dec(int64(len(gapped))) - } - // Delete the entire pending entry if it became empty. - if list.Empty() { - delete(pool.pending, addr) - } - } -} - -// addressByHeartbeat is an account address tagged with its last activity timestamp. -type addressByHeartbeat struct { - address common.Address - heartbeat time.Time -} - -type addressesByHeartbeat []addressByHeartbeat - -func (a addressesByHeartbeat) Len() int { return len(a) } -func (a addressesByHeartbeat) Less(i, j int) bool { return a[i].heartbeat.Before(a[j].heartbeat) } -func (a addressesByHeartbeat) Swap(i, j int) { a[i], a[j] = a[j], a[i] } - -// accountSet is simply a set of addresses to check for existence, and a signer -// capable of deriving addresses from transactions. -type accountSet struct { - accounts map[common.Address]struct{} - signer types.Signer - cache *[]common.Address -} - -// newAccountSet creates a new address set with an associated signer for sender -// derivations. -func newAccountSet(signer types.Signer, addrs ...common.Address) *accountSet { - as := &accountSet{ - accounts: make(map[common.Address]struct{}, len(addrs)), - signer: signer, - } - for _, addr := range addrs { - as.add(addr) - } - return as -} - -// contains checks if a given address is contained within the set. -func (as *accountSet) contains(addr common.Address) bool { - _, exist := as.accounts[addr] - return exist -} - -// containsTx checks if the sender of a given tx is within the set. If the sender -// cannot be derived, this method returns false. -func (as *accountSet) containsTx(tx *types.Transaction) bool { - if addr, err := types.Sender(as.signer, tx); err == nil { - return as.contains(addr) - } - return false -} - -// add inserts a new address into the set to track. -func (as *accountSet) add(addr common.Address) { - as.accounts[addr] = struct{}{} - as.cache = nil -} - -// addTx adds the sender of tx into the set. -func (as *accountSet) addTx(tx *types.Transaction) { - if addr, err := types.Sender(as.signer, tx); err == nil { - as.add(addr) - } -} - -// flatten returns the list of addresses within this set, also caching it for later -// 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 - } - 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{}{} - } - as.cache = nil -} - -// lookup is used internally by TxPool to track transactions while allowing -// lookup without mutex contention. -// -// Note, although this type is properly protected against concurrent access, it -// is **not** a type that should ever be mutated or even exposed outside of the -// transaction pool, since its internal state is tightly coupled with the pools -// internal mechanisms. The sole purpose of the type is to permit out-of-bound -// peeking into the pool in TxPool.Get without having to acquire the widely scoped -// TxPool.mu mutex. -// -// This lookup set combines the notion of "local transactions", which is useful -// to build upper-level structure. -type lookup struct { - slots int - lock sync.RWMutex - locals map[common.Hash]*types.Transaction - remotes map[common.Hash]*types.Transaction -} - -// newLookup returns a new lookup structure. -func newLookup() *lookup { - return &lookup{ - locals: make(map[common.Hash]*types.Transaction), - remotes: make(map[common.Hash]*types.Transaction), - } -} - -// Range calls f on each key and value present in the map. The callback passed -// should return the indicator whether the iteration needs to be continued. -// Callers need to specify which set (or both) to be iterated. -func (t *lookup) Range(f func(hash common.Hash, tx *types.Transaction, local bool) bool, local bool, remote bool) { - t.lock.RLock() - defer t.lock.RUnlock() - - if local { - for key, value := range t.locals { - if !f(key, value, true) { - return - } - } - } - if remote { - for key, value := range t.remotes { - if !f(key, value, false) { - return - } - } - } -} - -// Get returns a transaction if it exists in the lookup, or nil if not found. -func (t *lookup) Get(hash common.Hash) *types.Transaction { - t.lock.RLock() - defer t.lock.RUnlock() - - if tx := t.locals[hash]; tx != nil { - return tx - } - return t.remotes[hash] -} - -// GetLocal returns a transaction if it exists in the lookup, or nil if not found. -func (t *lookup) GetLocal(hash common.Hash) *types.Transaction { - t.lock.RLock() - defer t.lock.RUnlock() - - return t.locals[hash] -} - -// GetRemote returns a transaction if it exists in the lookup, or nil if not found. -func (t *lookup) GetRemote(hash common.Hash) *types.Transaction { - t.lock.RLock() - defer t.lock.RUnlock() - - return t.remotes[hash] -} - -// Count returns the current number of transactions in the lookup. -func (t *lookup) Count() int { - t.lock.RLock() - defer t.lock.RUnlock() - - return len(t.locals) + len(t.remotes) -} - -// LocalCount returns the current number of local transactions in the lookup. -func (t *lookup) LocalCount() int { - t.lock.RLock() - defer t.lock.RUnlock() - - return len(t.locals) -} - -// RemoteCount returns the current number of remote transactions in the lookup. -func (t *lookup) RemoteCount() int { - t.lock.RLock() - defer t.lock.RUnlock() - - return len(t.remotes) -} - -// Slots returns the current number of slots used in the lookup. -func (t *lookup) Slots() int { - t.lock.RLock() - defer t.lock.RUnlock() - - return t.slots -} - -// Add adds a transaction to the lookup. -func (t *lookup) Add(tx *types.Transaction, local bool) { - t.lock.Lock() - defer t.lock.Unlock() - - t.slots += numSlots(tx) - slotsGauge.Update(int64(t.slots)) - - if local { - t.locals[tx.Hash()] = tx - } else { - t.remotes[tx.Hash()] = tx - } -} - -// Remove removes a transaction from the lookup. -func (t *lookup) Remove(hash common.Hash) { - t.lock.Lock() - defer t.lock.Unlock() - - tx, ok := t.locals[hash] - if !ok { - tx, ok = t.remotes[hash] - } - if !ok { - log.Error("No transaction found to be deleted", "hash", hash) - return - } - t.slots -= numSlots(tx) - slotsGauge.Update(int64(t.slots)) - - delete(t.locals, hash) - delete(t.remotes, hash) -} - -// RemoteToLocals migrates the transactions belongs to the given locals to locals -// set. The assumption is held the locals set is thread-safe to be used. -func (t *lookup) RemoteToLocals(locals *accountSet) int { - t.lock.Lock() - defer t.lock.Unlock() - - var migrated int - for hash, tx := range t.remotes { - if locals.containsTx(tx) { - t.locals[hash] = tx - delete(t.remotes, hash) - migrated += 1 - } - } - return migrated -} - -// RemotesBelowTip finds all remote transactions below the given tip threshold. -func (t *lookup) RemotesBelowTip(threshold *big.Int) types.Transactions { - found := make(types.Transactions, 0, 128) - t.Range(func(hash common.Hash, tx *types.Transaction, local bool) bool { - if tx.GasTipCapIntCmp(threshold) < 0 { - found = append(found, tx) - } - return true - }, false, true) // Only iterate remotes - return found -} - -// numSlots calculates the number of slots needed for a single transaction. -func numSlots(tx *types.Transaction) int { - return int((tx.Size() + txSlotSize - 1) / txSlotSize) + return TxStatusUnknown } diff --git a/core/txpool/validation.go b/core/txpool/validation.go new file mode 100644 index 0000000000..630d5340cf --- /dev/null +++ b/core/txpool/validation.go @@ -0,0 +1,247 @@ +// 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 txpool + +import ( + "crypto/sha256" + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "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/crypto/kzg4844" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/params" +) + +// ValidationOptions define certain differences between transaction validation +// across the different pools without having to duplicate those checks. +type ValidationOptions struct { + Config *params.ChainConfig // Chain configuration to selectively validate based on current fork rules + + Accept uint8 // Bitmap of transaction types that should be accepted for the calling pool + MaxSize uint64 // Maximum size of a transaction that the caller can meaningfully handle + MinTip *big.Int // Minimum gas tip needed to allow a transaction into the caller pool +} + +// ValidateTransaction is a helper method to check whether a transaction is valid +// according to the consensus rules, but does not check state-dependent validation +// (balance, nonce, etc). +// +// This check is public to allow different transaction pools to check the basic +// rules without duplicating code and running the risk of missed updates. +func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types.Signer, opts *ValidationOptions) error { + // Ensure transactions not implemented by the calling pool are rejected + if opts.Accept&(1< opts.MaxSize { + return fmt.Errorf("%w: transaction size %v, limit %v", ErrOversizedData, tx.Size(), opts.MaxSize) + } + // Ensure only transactions that have been enabled are accepted + if !opts.Config.IsBerlin(head.Number) && tx.Type() != types.LegacyTxType { + return fmt.Errorf("%w: type %d rejected, pool not yet in Berlin", core.ErrTxTypeNotSupported, tx.Type()) + } + if !opts.Config.IsLondon(head.Number) && tx.Type() == types.DynamicFeeTxType { + return fmt.Errorf("%w: type %d rejected, pool not yet in London", core.ErrTxTypeNotSupported, tx.Type()) + } + if !opts.Config.IsCancun(head.Number, head.Time) && tx.Type() == types.BlobTxType { + return fmt.Errorf("%w: type %d rejected, pool not yet in Cancun", core.ErrTxTypeNotSupported, tx.Type()) + } + // Check whether the init code size has been exceeded + if opts.Config.IsShanghai(head.Number, head.Time) && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSize { + return fmt.Errorf("%w: code size %v, limit %v", core.ErrMaxInitCodeSizeExceeded, len(tx.Data()), params.MaxInitCodeSize) + } + // Transactions can't be negative. This may never happen using RLP decoded + // transactions but may occur for transactions created using the RPC. + if tx.Value().Sign() < 0 { + return ErrNegativeValue + } + // Ensure the transaction doesn't exceed the current block limit gas + if head.GasLimit < tx.Gas() { + return ErrGasLimit + } + // Sanity check for extremely large numbers (supported by RLP or RPC) + if tx.GasFeeCap().BitLen() > 256 { + return core.ErrFeeCapVeryHigh + } + if tx.GasTipCap().BitLen() > 256 { + return core.ErrTipVeryHigh + } + // Ensure gasFeeCap is greater than or equal to gasTipCap + if tx.GasFeeCapIntCmp(tx.GasTipCap()) < 0 { + return core.ErrTipAboveFeeCap + } + // Make sure the transaction is signed properly + if _, err := types.Sender(signer, tx); err != nil { + return ErrInvalidSender + } + // Ensure the transaction has more gas than the bare minimum needed to cover + // the transaction metadata + intrGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, true, opts.Config.IsIstanbul(head.Number), opts.Config.IsShanghai(head.Number, head.Time)) + if err != nil { + return err + } + if tx.Gas() < intrGas { + return fmt.Errorf("%w: needed %v, allowed %v", core.ErrIntrinsicGas, intrGas, tx.Gas()) + } + // Ensure the gasprice is high enough to cover the requirement of the calling + // pool and/or block producer + if tx.GasTipCapIntCmp(opts.MinTip) < 0 { + return fmt.Errorf("%w: tip needed %v, tip permitted %v", ErrUnderpriced, opts.MinTip, tx.GasTipCap()) + } + // Ensure blob transactions have valid commitments + if tx.Type() == types.BlobTxType { + sidecar := tx.BlobTxSidecar() + if sidecar == nil { + return fmt.Errorf("missing sidecar in blob transaction") + } + // Ensure the number of items in the blob transaction and vairous side + // data match up before doing any expensive validations + hashes := tx.BlobHashes() + if len(hashes) == 0 { + return fmt.Errorf("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) + } + if err := validateBlobSidecar(hashes, sidecar); err != nil { + return err + } + } + return nil +} + +func validateBlobSidecar(hashes []common.Hash, sidecar *types.BlobTxSidecar) error { + if len(sidecar.Blobs) != len(hashes) { + return fmt.Errorf("invalid number of %d blobs compared to %d blob hashes", len(sidecar.Blobs), len(hashes)) + } + if len(sidecar.Commitments) != len(hashes) { + return fmt.Errorf("invalid number of %d blob commitments compared to %d blob hashes", len(sidecar.Commitments), len(hashes)) + } + if len(sidecar.Proofs) != len(hashes) { + return fmt.Errorf("invalid number of %d blob proofs compared to %d blob hashes", len(sidecar.Proofs), len(hashes)) + } + // Blob quantities match up, validate that the provers match with the + // transaction hash before getting to the cryptography + hasher := sha256.New() + for i, want := range hashes { + hasher.Write(sidecar.Commitments[i][:]) + hash := hasher.Sum(nil) + hasher.Reset() + + var vhash common.Hash + vhash[0] = params.BlobTxHashVersion + copy(vhash[1:], hash[1:]) + + if vhash != want { + return fmt.Errorf("blob %d: computed hash %#x mismatches transaction one %#x", i, vhash, want) + } + } + // 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 { + return fmt.Errorf("invalid blob %d: %v", i, err) + } + } + return nil +} + +// ValidationOptionsWithState define certain differences between stateful transaction +// validation across the different pools without having to duplicate those checks. +type ValidationOptionsWithState struct { + State *state.StateDB // State database to check nonces and balances against + + // FirstNonceGap is an optional callback to retrieve the first nonce gap in + // the list of pooled transactions of a specific account. If this method is + // set, nonce gaps will be checked and forbidden. If this method is not set, + // nonce gaps will be ignored and permitted. + FirstNonceGap func(addr common.Address) uint64 + + // UsedAndLeftSlots is a mandatory callback to retrieve the number of tx slots + // used and the number still permitted for an account. New transactions will + // be rejected once the number of remaining slots reaches zero. + UsedAndLeftSlots func(addr common.Address) (int, int) + + // ExistingExpenditure is a mandatory callback to retrieve the cummulative + // cost of the already pooled transactions to check for overdrafts. + ExistingExpenditure func(addr common.Address) *big.Int + + // ExistingCost is a mandatory callback to retrieve an already pooled + // transaction's cost with the given nonce to check for overdrafts. + ExistingCost func(addr common.Address, nonce uint64) *big.Int +} + +// ValidateTransactionWithState is a helper method to check whether a transaction +// is valid according to the pool's internal state checks (balance, nonce, gaps). +// +// This check is public to allow different transaction pools to check the stateful +// 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 + if err != nil { + log.Error("Transaction sender recovery failed", "err", err) + return err + } + next := opts.State.GetNonce(from) + if next > tx.Nonce() { + return fmt.Errorf("%w: next nonce %v, tx nonce %v", core.ErrNonceTooLow, next, tx.Nonce()) + } + // Ensure the transaction doesn't produce a nonce gap in pools that do not + // support arbitrary orderings + if opts.FirstNonceGap != nil { + if gap := opts.FirstNonceGap(from); gap < tx.Nonce() { + return fmt.Errorf("%w: tx nonce %v, gapped nonce %v", core.ErrNonceTooHigh, tx.Nonce(), gap) + } + } + // Ensure the transactor has enough funds to cover the transaction costs + var ( + balance = opts.State.GetBalance(from) + cost = tx.Cost() + ) + if balance.Cmp(cost) < 0 { + return fmt.Errorf("%w: balance %v, tx cost %v, overshot %v", core.ErrInsufficientFunds, balance, cost, new(big.Int).Sub(cost, balance)) + } + // Ensure the transactor has enough funds to cover for replacements or nonce + // expansions without overdrafts + spent := opts.ExistingExpenditure(from) + if prev := opts.ExistingCost(from, tx.Nonce()); prev != nil { + bump := new(big.Int).Sub(cost, prev) + need := new(big.Int).Add(spent, bump) + if balance.Cmp(need) < 0 { + return fmt.Errorf("%w: balance %v, queued cost %v, tx bumped %v, overshot %v", core.ErrInsufficientFunds, balance, spent, bump, new(big.Int).Sub(need, balance)) + } + } else { + need := new(big.Int).Add(spent, cost) + if balance.Cmp(need) < 0 { + return fmt.Errorf("%w: balance %v, queued cost %v, tx cost %v, overshot %v", core.ErrInsufficientFunds, balance, spent, cost, new(big.Int).Sub(need, balance)) + } + // Transaction takes a new nonce value out of the pool. Ensure it doesn't + // overflow the number of permitted transactions from a single accoun + // (i.e. max cancellable via out-of-bound transaction). + if used, left := opts.UsedAndLeftSlots(from); left <= 0 { + return fmt.Errorf("%w: pooled %d txs", ErrAccountLimitExceeded, used) + } + } + return nil +} diff --git a/core/types/block.go b/core/types/block.go index a1a14f5b16..1a357baa3a 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -85,26 +85,28 @@ type Header struct { // WithdrawalsHash was added by EIP-4895 and is ignored in legacy headers. WithdrawalsHash *common.Hash `json:"withdrawalsRoot" rlp:"optional"` - // ExcessDataGas was added by EIP-4844 and is ignored in legacy headers. - ExcessDataGas *big.Int `json:"excessDataGas" rlp:"optional"` + // BlobGasUsed was added by EIP-4844 and is ignored in legacy headers. + BlobGasUsed *uint64 `json:"blobGasUsed" rlp:"optional"` - /* - TODO (MariusVanDerWijden) Add this field once needed - // Random was added during the merge and contains the BeaconState randomness - Random common.Hash `json:"random" rlp:"optional"` - */ + // ExcessBlobGas was added by EIP-4844 and is ignored in legacy headers. + ExcessBlobGas *uint64 `json:"excessBlobGas" rlp:"optional"` + + // ParentBeaconRoot was added by EIP-4788 and is ignored in legacy headers. + ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"` } // field type overrides for gencodec type headerMarshaling struct { - Difficulty *hexutil.Big - Number *hexutil.Big - GasLimit hexutil.Uint64 - GasUsed hexutil.Uint64 - Time hexutil.Uint64 - Extra hexutil.Bytes - BaseFee *hexutil.Big - Hash common.Hash `json:"hash"` // adds call to Hash() in MarshalJSON + Difficulty *hexutil.Big + Number *hexutil.Big + GasLimit hexutil.Uint64 + GasUsed hexutil.Uint64 + Time hexutil.Uint64 + Extra hexutil.Bytes + BaseFee *hexutil.Big + Hash common.Hash `json:"hash"` // adds call to Hash() in MarshalJSON + BlobGasUsed *hexutil.Uint64 + ExcessBlobGas *hexutil.Uint64 } // Hash returns the block hash of the header, which is simply the keccak256 hash of its @@ -152,10 +154,10 @@ 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.UncleHash == EmptyUncleHash + if h.WithdrawalsHash != nil { + return h.TxHash == EmptyTxsHash && *h.WithdrawalsHash == EmptyWithdrawalsHash } - return h.TxHash == EmptyTxsHash && h.UncleHash == EmptyUncleHash && *h.WithdrawalsHash == EmptyWithdrawalsHash + return h.TxHash == EmptyTxsHash && h.UncleHash == EmptyUncleHash } // EmptyReceipts returns true if there are no receipts for this header/block. @@ -171,7 +173,23 @@ type Body struct { Withdrawals []*Withdrawal `rlp:"optional"` } -// Block represents an entire block in the Ethereum blockchain. +// Block represents an Ethereum block. +// +// Note the Block type tries to be 'immutable', and contains certain caches that rely +// on that. The rules around block immutability are as follows: +// +// - We copy all data when the block is constructed. This makes references held inside +// the block independent of whatever value was passed in. +// +// - We copy all header data on access. This is because any change to the header would mess +// up the cached hash and size values in the block. Calling code is expected to take +// advantage of this to avoid over-allocating! +// +// - When new body data is attached to the block, a shallow copy of the block is returned. +// This ensures block modifications are race-free. +// +// - We do not copy body data on access because it does not affect the caches, and also +// because it would be too expensive. type Block struct { header *Header uncles []*Header @@ -196,9 +214,8 @@ type extblock struct { Withdrawals []*Withdrawal `rlp:"optional"` } -// NewBlock creates a new block. The input data is copied, -// changes to header and to the field values will not affect the -// block. +// 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 @@ -235,13 +252,11 @@ 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. +// 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. +// 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) @@ -257,15 +272,7 @@ func NewBlockWithWithdrawals(header *Header, txs []*Transaction, uncles []*Heade return b.WithWithdrawals(withdrawals) } -// NewBlockWithHeader creates a block with the given header data. The -// header data is copied, changes to header and to the field values -// will not affect the block. -func NewBlockWithHeader(header *Header) *Block { - return &Block{header: CopyHeader(header)} -} - -// CopyHeader creates a deep copy of a block header to prevent side effects from -// modifying a header variable. +// CopyHeader creates a deep copy of a block header. func CopyHeader(h *Header) *Header { cpy := *h if cpy.Difficulty = new(big.Int); h.Difficulty != nil { @@ -285,10 +292,22 @@ func CopyHeader(h *Header) *Header { cpy.WithdrawalsHash = new(common.Hash) *cpy.WithdrawalsHash = *h.WithdrawalsHash } + if h.ExcessBlobGas != nil { + cpy.ExcessBlobGas = new(uint64) + *cpy.ExcessBlobGas = *h.ExcessBlobGas + } + if h.BlobGasUsed != nil { + cpy.BlobGasUsed = new(uint64) + *cpy.BlobGasUsed = *h.BlobGasUsed + } + if h.ParentBeaconRoot != nil { + cpy.ParentBeaconRoot = new(common.Hash) + *cpy.ParentBeaconRoot = *h.ParentBeaconRoot + } return &cpy } -// DecodeRLP decodes the Ethereum +// DecodeRLP decodes a block from RLP. func (b *Block) DecodeRLP(s *rlp.Stream) error { var eb extblock _, size, _ := s.Kind() @@ -300,9 +319,9 @@ func (b *Block) DecodeRLP(s *rlp.Stream) error { return nil } -// EncodeRLP serializes b into the Ethereum RLP block format. +// EncodeRLP serializes a block as RLP. func (b *Block) EncodeRLP(w io.Writer) error { - return rlp.Encode(w, extblock{ + return rlp.Encode(w, &extblock{ Header: b.header, Txs: b.transactions, Uncles: b.uncles, @@ -310,10 +329,18 @@ func (b *Block) EncodeRLP(w io.Writer) error { }) } -// TODO: copies +// 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} +} + +// Accessors for body data. These do not return a copy because the content +// of the body slices does not affect the cached hash/size in block. 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) Transaction(hash common.Hash) *Transaction { for _, transaction := range b.transactions { @@ -324,6 +351,13 @@ func (b *Block) Transaction(hash common.Hash) *Transaction { return nil } +// Header returns the block header (as a copy). +func (b *Block) Header() *Header { + return CopyHeader(b.header) +} + +// Header value accessors. These do copy! + func (b *Block) Number() *big.Int { return new(big.Int).Set(b.header.Number) } func (b *Block) GasLimit() uint64 { return b.header.GasLimit } func (b *Block) GasUsed() uint64 { return b.header.GasUsed } @@ -349,14 +383,25 @@ func (b *Block) BaseFee() *big.Int { return new(big.Int).Set(b.header.BaseFee) } -func (b *Block) Withdrawals() Withdrawals { - return b.withdrawals +func (b *Block) BeaconRoot() *common.Hash { return b.header.ParentBeaconRoot } + +func (b *Block) ExcessBlobGas() *uint64 { + var excessBlobGas *uint64 + if b.header.ExcessBlobGas != nil { + excessBlobGas = new(uint64) + *excessBlobGas = *b.header.ExcessBlobGas + } + return excessBlobGas } -func (b *Block) Header() *Header { return CopyHeader(b.header) } - -// Body returns the non-header content of the block. -func (b *Block) Body() *Body { return &Body{b.transactions, b.uncles, b.withdrawals} } +func (b *Block) BlobGasUsed() *uint64 { + var blobGasUsed *uint64 + if b.header.BlobGasUsed != nil { + blobGasUsed = new(uint64) + *blobGasUsed = *b.header.BlobGasUsed + } + return blobGasUsed +} // Size returns the true RLP encoded storage size of the block, either by encoding // and returning it, or returning a previously cached value. @@ -390,25 +435,31 @@ func CalcUncleHash(uncles []*Header) common.Hash { return rlpHash(uncles) } +// NewBlockWithHeader creates a block with the given header data. The +// header data is copied, changes to header and to the field values +// will not affect the block. +func NewBlockWithHeader(header *Header) *Block { + return &Block{header: CopyHeader(header)} +} + // WithSeal returns a new block with the data from b but the header replaced with // the sealed one. func (b *Block) WithSeal(header *Header) *Block { - cpy := *header - return &Block{ - header: &cpy, + header: CopyHeader(header), transactions: b.transactions, uncles: b.uncles, withdrawals: b.withdrawals, } } -// WithBody returns a new block with the given transaction and uncle contents. +// 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: CopyHeader(b.header), + header: b.header, transactions: make([]*Transaction, len(transactions)), uncles: make([]*Header, len(uncles)), + withdrawals: b.withdrawals, } copy(block.transactions, transactions) for i := range uncles { @@ -417,13 +468,18 @@ func (b *Block) WithBody(transactions []*Transaction, uncles []*Header) *Block { return block } -// WithWithdrawals sets the withdrawal contents of a block, does not return a new block. +// WithWithdrawals returns a copy of the block containing the given withdrawals. func (b *Block) WithWithdrawals(withdrawals []*Withdrawal) *Block { - if withdrawals != nil { - b.withdrawals = make([]*Withdrawal, len(withdrawals)) - copy(b.withdrawals, withdrawals) + block := &Block{ + header: b.header, + transactions: b.transactions, + uncles: b.uncles, } - return b + if withdrawals != nil { + block.withdrawals = make([]*Withdrawal, len(withdrawals)) + copy(block.withdrawals, withdrawals) + } + return block } // Hash returns the keccak256 hash of b's header. diff --git a/core/types/block_test.go b/core/types/block_test.go index 966015eb01..cf0b1dd85c 100644 --- a/core/types/block_test.go +++ b/core/types/block_test.go @@ -18,7 +18,6 @@ package types import ( "bytes" - "hash" "math/big" "reflect" "testing" @@ -26,9 +25,9 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/internal/blocktest" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" - "golang.org/x/crypto/sha3" ) // from bcValidBlockTest.json, "SimpleTx" @@ -217,31 +216,6 @@ func BenchmarkEncodeBlock(b *testing.B) { } } -// testHasher is the helper tool for transaction/receipt list hashing. -// The original hasher is trie, in order to get rid of import cycle, -// use the testing hasher instead. -type testHasher struct { - hasher hash.Hash -} - -func newHasher() *testHasher { - return &testHasher{hasher: sha3.NewLegacyKeccak256()} -} - -func (h *testHasher) Reset() { - h.hasher.Reset() -} - -func (h *testHasher) Update(key, val []byte) error { - h.hasher.Write(key) - h.hasher.Write(val) - return nil -} - -func (h *testHasher) Hash() common.Hash { - return common.BytesToHash(h.hasher.Sum(nil)) -} - func makeBenchBlock() *Block { var ( key, _ = crypto.GenerateKey() @@ -280,7 +254,7 @@ func makeBenchBlock() *Block { Extra: []byte("benchmark uncle"), } } - return NewBlock(header, txs, uncles, receipts, newHasher()) + return NewBlock(header, txs, uncles, receipts, blocktest.NewHasher()) } func TestRlpDecodeParentHash(t *testing.T) { diff --git a/core/types/gen_header_json.go b/core/types/gen_header_json.go index 73287257bd..fb1f915d01 100644 --- a/core/types/gen_header_json.go +++ b/core/types/gen_header_json.go @@ -16,25 +16,27 @@ var _ = (*headerMarshaling)(nil) // MarshalJSON marshals as JSON. func (h Header) MarshalJSON() ([]byte, error) { type Header struct { - ParentHash common.Hash `json:"parentHash" gencodec:"required"` - UncleHash common.Hash `json:"sha3Uncles" gencodec:"required"` - Coinbase common.Address `json:"miner"` - Root common.Hash `json:"stateRoot" gencodec:"required"` - TxHash common.Hash `json:"transactionsRoot" gencodec:"required"` - ReceiptHash common.Hash `json:"receiptsRoot" gencodec:"required"` - Bloom Bloom `json:"logsBloom" gencodec:"required"` - Difficulty *hexutil.Big `json:"difficulty" gencodec:"required"` - Number *hexutil.Big `json:"number" gencodec:"required"` - GasLimit hexutil.Uint64 `json:"gasLimit" gencodec:"required"` - GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"` - Time hexutil.Uint64 `json:"timestamp" gencodec:"required"` - Extra hexutil.Bytes `json:"extraData" gencodec:"required"` - MixDigest common.Hash `json:"mixHash"` - Nonce BlockNonce `json:"nonce"` - BaseFee *hexutil.Big `json:"baseFeePerGas" rlp:"optional"` - WithdrawalsHash *common.Hash `json:"withdrawalsRoot" rlp:"optional"` - ExcessDataGas *big.Int `json:"excessDataGas" rlp:"optional"` - Hash common.Hash `json:"hash"` + ParentHash common.Hash `json:"parentHash" gencodec:"required"` + UncleHash common.Hash `json:"sha3Uncles" gencodec:"required"` + Coinbase common.Address `json:"miner"` + Root common.Hash `json:"stateRoot" gencodec:"required"` + TxHash common.Hash `json:"transactionsRoot" gencodec:"required"` + ReceiptHash common.Hash `json:"receiptsRoot" gencodec:"required"` + Bloom Bloom `json:"logsBloom" gencodec:"required"` + Difficulty *hexutil.Big `json:"difficulty" gencodec:"required"` + Number *hexutil.Big `json:"number" gencodec:"required"` + GasLimit hexutil.Uint64 `json:"gasLimit" gencodec:"required"` + GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"` + Time hexutil.Uint64 `json:"timestamp" gencodec:"required"` + Extra hexutil.Bytes `json:"extraData" gencodec:"required"` + MixDigest common.Hash `json:"mixHash"` + Nonce BlockNonce `json:"nonce"` + BaseFee *hexutil.Big `json:"baseFeePerGas" rlp:"optional"` + WithdrawalsHash *common.Hash `json:"withdrawalsRoot" rlp:"optional"` + BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed" rlp:"optional"` + ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas" rlp:"optional"` + ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"` + Hash common.Hash `json:"hash"` } var enc Header enc.ParentHash = h.ParentHash @@ -54,7 +56,9 @@ func (h Header) MarshalJSON() ([]byte, error) { enc.Nonce = h.Nonce enc.BaseFee = (*hexutil.Big)(h.BaseFee) enc.WithdrawalsHash = h.WithdrawalsHash - enc.ExcessDataGas = h.ExcessDataGas + enc.BlobGasUsed = (*hexutil.Uint64)(h.BlobGasUsed) + enc.ExcessBlobGas = (*hexutil.Uint64)(h.ExcessBlobGas) + enc.ParentBeaconRoot = h.ParentBeaconRoot enc.Hash = h.Hash() return json.Marshal(&enc) } @@ -62,24 +66,26 @@ func (h Header) MarshalJSON() ([]byte, error) { // UnmarshalJSON unmarshals from JSON. func (h *Header) UnmarshalJSON(input []byte) error { type Header struct { - ParentHash *common.Hash `json:"parentHash" gencodec:"required"` - UncleHash *common.Hash `json:"sha3Uncles" gencodec:"required"` - Coinbase *common.Address `json:"miner"` - Root *common.Hash `json:"stateRoot" gencodec:"required"` - TxHash *common.Hash `json:"transactionsRoot" gencodec:"required"` - ReceiptHash *common.Hash `json:"receiptsRoot" gencodec:"required"` - Bloom *Bloom `json:"logsBloom" gencodec:"required"` - Difficulty *hexutil.Big `json:"difficulty" gencodec:"required"` - Number *hexutil.Big `json:"number" gencodec:"required"` - GasLimit *hexutil.Uint64 `json:"gasLimit" gencodec:"required"` - GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"` - Time *hexutil.Uint64 `json:"timestamp" gencodec:"required"` - Extra *hexutil.Bytes `json:"extraData" gencodec:"required"` - MixDigest *common.Hash `json:"mixHash"` - Nonce *BlockNonce `json:"nonce"` - BaseFee *hexutil.Big `json:"baseFeePerGas" rlp:"optional"` - WithdrawalsHash *common.Hash `json:"withdrawalsRoot" rlp:"optional"` - ExcessDataGas *big.Int `json:"excessDataGas" rlp:"optional"` + ParentHash *common.Hash `json:"parentHash" gencodec:"required"` + UncleHash *common.Hash `json:"sha3Uncles" gencodec:"required"` + Coinbase *common.Address `json:"miner"` + Root *common.Hash `json:"stateRoot" gencodec:"required"` + TxHash *common.Hash `json:"transactionsRoot" gencodec:"required"` + ReceiptHash *common.Hash `json:"receiptsRoot" gencodec:"required"` + Bloom *Bloom `json:"logsBloom" gencodec:"required"` + Difficulty *hexutil.Big `json:"difficulty" gencodec:"required"` + Number *hexutil.Big `json:"number" gencodec:"required"` + GasLimit *hexutil.Uint64 `json:"gasLimit" gencodec:"required"` + GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"` + Time *hexutil.Uint64 `json:"timestamp" gencodec:"required"` + Extra *hexutil.Bytes `json:"extraData" gencodec:"required"` + MixDigest *common.Hash `json:"mixHash"` + Nonce *BlockNonce `json:"nonce"` + BaseFee *hexutil.Big `json:"baseFeePerGas" rlp:"optional"` + WithdrawalsHash *common.Hash `json:"withdrawalsRoot" rlp:"optional"` + BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed" rlp:"optional"` + ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas" rlp:"optional"` + ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"` } var dec Header if err := json.Unmarshal(input, &dec); err != nil { @@ -148,8 +154,14 @@ func (h *Header) UnmarshalJSON(input []byte) error { if dec.WithdrawalsHash != nil { h.WithdrawalsHash = dec.WithdrawalsHash } - if dec.ExcessDataGas != nil { - h.ExcessDataGas = dec.ExcessDataGas + if dec.BlobGasUsed != nil { + h.BlobGasUsed = (*uint64)(dec.BlobGasUsed) + } + if dec.ExcessBlobGas != nil { + h.ExcessBlobGas = (*uint64)(dec.ExcessBlobGas) + } + if dec.ParentBeaconRoot != nil { + h.ParentBeaconRoot = dec.ParentBeaconRoot } return nil } diff --git a/core/types/gen_header_rlp.go b/core/types/gen_header_rlp.go index 005f6c2ad4..b91a255a55 100644 --- a/core/types/gen_header_rlp.go +++ b/core/types/gen_header_rlp.go @@ -42,8 +42,10 @@ func (obj *Header) EncodeRLP(_w io.Writer) error { w.WriteBytes(obj.Nonce[:]) _tmp1 := obj.BaseFee != nil _tmp2 := obj.WithdrawalsHash != nil - _tmp3 := obj.ExcessDataGas != nil - if _tmp1 || _tmp2 || _tmp3 { + _tmp3 := obj.BlobGasUsed != nil + _tmp4 := obj.ExcessBlobGas != nil + _tmp5 := obj.ParentBeaconRoot != nil + if _tmp1 || _tmp2 || _tmp3 || _tmp4 || _tmp5 { if obj.BaseFee == nil { w.Write(rlp.EmptyString) } else { @@ -53,21 +55,32 @@ func (obj *Header) EncodeRLP(_w io.Writer) error { w.WriteBigInt(obj.BaseFee) } } - if _tmp2 || _tmp3 { + if _tmp2 || _tmp3 || _tmp4 || _tmp5 { if obj.WithdrawalsHash == nil { w.Write([]byte{0x80}) } else { w.WriteBytes(obj.WithdrawalsHash[:]) } } - if _tmp3 { - if obj.ExcessDataGas == nil { - w.Write(rlp.EmptyString) + if _tmp3 || _tmp4 || _tmp5 { + if obj.BlobGasUsed == nil { + w.Write([]byte{0x80}) } else { - if obj.ExcessDataGas.Sign() == -1 { - return rlp.ErrNegativeBigInt - } - w.WriteBigInt(obj.ExcessDataGas) + w.WriteUint64((*obj.BlobGasUsed)) + } + } + if _tmp4 || _tmp5 { + if obj.ExcessBlobGas == nil { + w.Write([]byte{0x80}) + } else { + w.WriteUint64((*obj.ExcessBlobGas)) + } + } + if _tmp5 { + if obj.ParentBeaconRoot == nil { + w.Write([]byte{0x80}) + } else { + w.WriteBytes(obj.ParentBeaconRoot[:]) } } w.ListEnd(_tmp0) diff --git a/core/types/gen_log_json.go b/core/types/gen_log_json.go index 90e1c14d90..3ffa9c2feb 100644 --- a/core/types/gen_log_json.go +++ b/core/types/gen_log_json.go @@ -18,12 +18,12 @@ func (l Log) MarshalJSON() ([]byte, error) { Address common.Address `json:"address" gencodec:"required"` Topics []common.Hash `json:"topics" gencodec:"required"` Data hexutil.Bytes `json:"data" gencodec:"required"` - BlockNumber hexutil.Uint64 `json:"blockNumber"` - TxHash common.Hash `json:"transactionHash" gencodec:"required"` - TxIndex hexutil.Uint `json:"transactionIndex"` - BlockHash common.Hash `json:"blockHash"` - Index hexutil.Uint `json:"logIndex"` - Removed bool `json:"removed"` + BlockNumber hexutil.Uint64 `json:"blockNumber" rlp:"-"` + TxHash common.Hash `json:"transactionHash" gencodec:"required" rlp:"-"` + TxIndex hexutil.Uint `json:"transactionIndex" rlp:"-"` + BlockHash common.Hash `json:"blockHash" rlp:"-"` + Index hexutil.Uint `json:"logIndex" rlp:"-"` + Removed bool `json:"removed" rlp:"-"` } var enc Log enc.Address = l.Address @@ -44,12 +44,12 @@ func (l *Log) UnmarshalJSON(input []byte) error { Address *common.Address `json:"address" gencodec:"required"` Topics []common.Hash `json:"topics" gencodec:"required"` Data *hexutil.Bytes `json:"data" gencodec:"required"` - BlockNumber *hexutil.Uint64 `json:"blockNumber"` - TxHash *common.Hash `json:"transactionHash" gencodec:"required"` - TxIndex *hexutil.Uint `json:"transactionIndex"` - BlockHash *common.Hash `json:"blockHash"` - Index *hexutil.Uint `json:"logIndex"` - Removed *bool `json:"removed"` + BlockNumber *hexutil.Uint64 `json:"blockNumber" rlp:"-"` + TxHash *common.Hash `json:"transactionHash" gencodec:"required" rlp:"-"` + TxIndex *hexutil.Uint `json:"transactionIndex" rlp:"-"` + BlockHash *common.Hash `json:"blockHash" rlp:"-"` + Index *hexutil.Uint `json:"logIndex" rlp:"-"` + Removed *bool `json:"removed" rlp:"-"` } var dec Log if err := json.Unmarshal(input, &dec); err != nil { diff --git a/core/types/gen_log_rlp.go b/core/types/gen_log_rlp.go index 4a6c6b0094..cbdb6736e2 100644 --- a/core/types/gen_log_rlp.go +++ b/core/types/gen_log_rlp.go @@ -8,7 +8,7 @@ package types import "github.com/ethereum/go-ethereum/rlp" import "io" -func (obj *rlpLog) EncodeRLP(_w io.Writer) error { +func (obj *Log) EncodeRLP(_w io.Writer) error { w := rlp.NewEncoderBuffer(_w) _tmp0 := w.List() w.WriteBytes(obj.Address[:]) diff --git a/core/types/gen_receipt_json.go b/core/types/gen_receipt_json.go index d83be14477..4c641a9727 100644 --- a/core/types/gen_receipt_json.go +++ b/core/types/gen_receipt_json.go @@ -26,6 +26,8 @@ func (r Receipt) MarshalJSON() ([]byte, error) { ContractAddress common.Address `json:"contractAddress"` GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"` EffectiveGasPrice *hexutil.Big `json:"effectiveGasPrice"` + BlobGasUsed hexutil.Uint64 `json:"blobGasUsed,omitempty"` + BlobGasPrice *hexutil.Big `json:"blobGasPrice,omitempty"` BlockHash common.Hash `json:"blockHash,omitempty"` BlockNumber *hexutil.Big `json:"blockNumber,omitempty"` TransactionIndex hexutil.Uint `json:"transactionIndex"` @@ -41,6 +43,8 @@ func (r Receipt) MarshalJSON() ([]byte, error) { enc.ContractAddress = r.ContractAddress enc.GasUsed = hexutil.Uint64(r.GasUsed) enc.EffectiveGasPrice = (*hexutil.Big)(r.EffectiveGasPrice) + enc.BlobGasUsed = hexutil.Uint64(r.BlobGasUsed) + enc.BlobGasPrice = (*hexutil.Big)(r.BlobGasPrice) enc.BlockHash = r.BlockHash enc.BlockNumber = (*hexutil.Big)(r.BlockNumber) enc.TransactionIndex = hexutil.Uint(r.TransactionIndex) @@ -60,6 +64,8 @@ func (r *Receipt) UnmarshalJSON(input []byte) error { ContractAddress *common.Address `json:"contractAddress"` GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"` EffectiveGasPrice *hexutil.Big `json:"effectiveGasPrice"` + BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed,omitempty"` + BlobGasPrice *hexutil.Big `json:"blobGasPrice,omitempty"` BlockHash *common.Hash `json:"blockHash,omitempty"` BlockNumber *hexutil.Big `json:"blockNumber,omitempty"` TransactionIndex *hexutil.Uint `json:"transactionIndex"` @@ -103,6 +109,12 @@ func (r *Receipt) UnmarshalJSON(input []byte) error { if dec.EffectiveGasPrice != nil { r.EffectiveGasPrice = (*big.Int)(dec.EffectiveGasPrice) } + if dec.BlobGasUsed != nil { + r.BlobGasUsed = uint64(*dec.BlobGasUsed) + } + if dec.BlobGasPrice != nil { + r.BlobGasPrice = (*big.Int)(dec.BlobGasPrice) + } if dec.BlockHash != nil { r.BlockHash = *dec.BlockHash } diff --git a/core/types/hashes.go b/core/types/hashes.go index 3bad430be5..3a787aa136 100644 --- a/core/types/hashes.go +++ b/core/types/hashes.go @@ -19,6 +19,7 @@ package types import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/log" ) var ( @@ -40,3 +41,13 @@ var ( // EmptyWithdrawalsHash is the known hash of the empty withdrawal set. EmptyWithdrawalsHash = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") ) + +// TrieRootHash returns the hash itself if it's non-empty or the predefined +// emptyHash one instead. +func TrieRootHash(hash common.Hash) common.Hash { + if hash == (common.Hash{}) { + log.Error("Zero trie root hash!") + return EmptyRootHash + } + return hash +} diff --git a/core/types/hashing.go b/core/types/hashing.go index fbdeaf0d07..9a6a80ac52 100644 --- a/core/types/hashing.go +++ b/core/types/hashing.go @@ -18,6 +18,8 @@ package types import ( "bytes" + "fmt" + "math" "sync" "github.com/ethereum/go-ethereum/common" @@ -36,6 +38,22 @@ var encodeBufferPool = sync.Pool{ New: func() interface{} { return new(bytes.Buffer) }, } +// getPooledBuffer retrieves a buffer from the pool and creates a byte slice of the +// requested size from it. +// +// The caller should return the *bytes.Buffer object back into encodeBufferPool after use! +// The returned byte slice must not be used after returning the buffer. +func getPooledBuffer(size uint64) ([]byte, *bytes.Buffer, error) { + if size > math.MaxInt { + return nil, nil, fmt.Errorf("can't get buffer of size %d", size) + } + buf := encodeBufferPool.Get().(*bytes.Buffer) + buf.Reset() + buf.Grow(int(size)) + b := buf.Bytes()[:int(size)] + return b, buf, nil +} + // rlpHash encodes x and hashes the encoded bytes. func rlpHash(x interface{}) (h common.Hash) { sha := hasherPool.Get().(crypto.KeccakState) diff --git a/core/types/hashing_test.go b/core/types/hashing_test.go index c5b9f690d8..d2a98ed7bf 100644 --- a/core/types/hashing_test.go +++ b/core/types/hashing_test.go @@ -39,7 +39,7 @@ func TestDeriveSha(t *testing.T) { t.Fatal(err) } for len(txs) < 1000 { - exp := types.DeriveSha(txs, trie.NewEmpty(trie.NewDatabase(rawdb.NewMemoryDatabase()))) + exp := types.DeriveSha(txs, trie.NewEmpty(trie.NewDatabase(rawdb.NewMemoryDatabase(), nil))) got := types.DeriveSha(txs, trie.NewStackTrie(nil)) if !bytes.Equal(got[:], exp[:]) { t.Fatalf("%d txs: got %x exp %x", len(txs), got, exp) @@ -86,7 +86,7 @@ func BenchmarkDeriveSha200(b *testing.B) { b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { - exp = types.DeriveSha(txs, trie.NewEmpty(trie.NewDatabase(rawdb.NewMemoryDatabase()))) + exp = types.DeriveSha(txs, trie.NewEmpty(trie.NewDatabase(rawdb.NewMemoryDatabase(), nil))) } }) @@ -107,7 +107,7 @@ func TestFuzzDeriveSha(t *testing.T) { rndSeed := mrand.Int() for i := 0; i < 10; i++ { seed := rndSeed + i - exp := types.DeriveSha(newDummy(i), trie.NewEmpty(trie.NewDatabase(rawdb.NewMemoryDatabase()))) + exp := types.DeriveSha(newDummy(i), trie.NewEmpty(trie.NewDatabase(rawdb.NewMemoryDatabase(), nil))) got := types.DeriveSha(newDummy(i), trie.NewStackTrie(nil)) if !bytes.Equal(got[:], exp[:]) { printList(newDummy(seed)) @@ -135,7 +135,7 @@ func TestDerivableList(t *testing.T) { }, } for i, tc := range tcs[1:] { - exp := types.DeriveSha(flatList(tc), trie.NewEmpty(trie.NewDatabase(rawdb.NewMemoryDatabase()))) + exp := types.DeriveSha(flatList(tc), trie.NewEmpty(trie.NewDatabase(rawdb.NewMemoryDatabase(), nil))) got := types.DeriveSha(flatList(tc), trie.NewStackTrie(nil)) if !bytes.Equal(got[:], exp[:]) { t.Fatalf("case %d: got %x exp %x", i, got, exp) diff --git a/core/types/log.go b/core/types/log.go index e489191368..54c7ff6372 100644 --- a/core/types/log.go +++ b/core/types/log.go @@ -17,13 +17,11 @@ package types import ( - "io" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/rlp" ) +//go:generate go run ../../rlp/rlpgen -type Log -out gen_log_rlp.go //go:generate go run github.com/fjl/gencodec -type Log -field-override logMarshaling -out gen_log_json.go // Log represents a contract log event. These events are generated by the LOG opcode and @@ -40,19 +38,19 @@ type Log struct { // Derived fields. These fields are filled in by the node // but not secured by consensus. // block in which the transaction was included - BlockNumber uint64 `json:"blockNumber"` + BlockNumber uint64 `json:"blockNumber" rlp:"-"` // hash of the transaction - TxHash common.Hash `json:"transactionHash" gencodec:"required"` + TxHash common.Hash `json:"transactionHash" gencodec:"required" rlp:"-"` // index of the transaction in the block - TxIndex uint `json:"transactionIndex"` + TxIndex uint `json:"transactionIndex" rlp:"-"` // hash of the block in which the transaction was included - BlockHash common.Hash `json:"blockHash"` + BlockHash common.Hash `json:"blockHash" rlp:"-"` // index of the log in the block - Index uint `json:"logIndex"` + Index uint `json:"logIndex" rlp:"-"` // The Removed field is true if this log was reverted due to a chain reorganisation. // You must pay attention to this field if you receive logs through a filter query. - Removed bool `json:"removed"` + Removed bool `json:"removed" rlp:"-"` } type logMarshaling struct { @@ -61,28 +59,3 @@ type logMarshaling struct { TxIndex hexutil.Uint Index hexutil.Uint } - -//go:generate go run ../../rlp/rlpgen -type rlpLog -out gen_log_rlp.go - -// rlpLog is used to RLP-encode both the consensus and storage formats. -type rlpLog struct { - Address common.Address - Topics []common.Hash - Data []byte -} - -// EncodeRLP implements rlp.Encoder. -func (l *Log) EncodeRLP(w io.Writer) error { - rl := rlpLog{Address: l.Address, Topics: l.Topics, Data: l.Data} - return rlp.Encode(w, &rl) -} - -// DecodeRLP implements rlp.Decoder. -func (l *Log) DecodeRLP(s *rlp.Stream) error { - var dec rlpLog - err := s.Decode(&dec) - if err == nil { - l.Address, l.Topics, l.Data = dec.Address, dec.Topics, dec.Data - } - return err -} diff --git a/core/types/log_test.go b/core/types/log_test.go index 0e56acfe4a..02eef3ecd4 100644 --- a/core/types/log_test.go +++ b/core/types/log_test.go @@ -18,7 +18,7 @@ package types import ( "encoding/json" - "fmt" + "errors" "reflect" "testing" @@ -97,7 +97,7 @@ var unmarshalLogTests = map[string]struct { }, "missing data": { input: `{"address":"0xecf8f87f810ecf450940c9f60066b4a7a501d6a7","blockHash":"0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056","blockNumber":"0x1ecfa4","logIndex":"0x2","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x00000000000000000000000080b2c9d7cbbf30a1b0fc8983c647d754c6525615","0x000000000000000000000000f9dff387dcb5cc4cca5b91adb07a95f54e9f1bb6"],"transactionHash":"0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e","transactionIndex":"0x3"}`, - wantError: fmt.Errorf("missing required field 'data' for Log"), + wantError: errors.New("missing required field 'data' for Log"), }, } diff --git a/core/types/receipt.go b/core/types/receipt.go index 8fc9ec9894..4f96fde59c 100644 --- a/core/types/receipt.go +++ b/core/types/receipt.go @@ -63,6 +63,8 @@ type Receipt struct { ContractAddress common.Address `json:"contractAddress"` GasUsed uint64 `json:"gasUsed" gencodec:"required"` EffectiveGasPrice *big.Int `json:"effectiveGasPrice"` // required, but tag omitted for backwards compatibility + BlobGasUsed uint64 `json:"blobGasUsed,omitempty"` + BlobGasPrice *big.Int `json:"blobGasPrice,omitempty"` // Inclusion information: These fields provide information about the inclusion of the // transaction corresponding to this receipt. @@ -78,6 +80,8 @@ type receiptMarshaling struct { CumulativeGasUsed hexutil.Uint64 GasUsed hexutil.Uint64 EffectiveGasPrice *hexutil.Big + BlobGasUsed hexutil.Uint64 + BlobGasPrice *hexutil.Big BlockNumber *hexutil.Big TransactionIndex hexutil.Uint } @@ -149,7 +153,7 @@ func (r *Receipt) MarshalBinary() ([]byte, error) { // DecodeRLP implements rlp.Decoder, and loads the consensus fields of a receipt // from an RLP stream. func (r *Receipt) DecodeRLP(s *rlp.Stream) error { - kind, _, err := s.Kind() + kind, size, err := s.Kind() switch { case err != nil: return err @@ -161,12 +165,18 @@ func (r *Receipt) DecodeRLP(s *rlp.Stream) error { } r.Type = LegacyTxType return r.setFromRLP(dec) + case kind == rlp.Byte: + return errShortTypedReceipt default: // It's an EIP-2718 typed tx receipt. - b, err := s.Bytes() + b, buf, err := getPooledBuffer(size) if err != nil { return err } + defer encodeBufferPool.Put(buf) + if err := s.ReadBytes(b); err != nil { + return err + } return r.decodeTyped(b) } } @@ -194,7 +204,7 @@ func (r *Receipt) decodeTyped(b []byte) error { return errShortTypedReceipt } switch b[0] { - case DynamicFeeTxType, AccessListTxType: + case DynamicFeeTxType, AccessListTxType, BlobTxType: var data receiptRLP err := rlp.DecodeBytes(b[1:], &data) if err != nil { @@ -260,7 +270,7 @@ func (r *ReceiptForStorage) EncodeRLP(_w io.Writer) error { w.WriteUint64(r.CumulativeGasUsed) logList := w.List() for _, log := range r.Logs { - if err := rlp.Encode(w, log); err != nil { + if err := log.EncodeRLP(w); err != nil { return err } } @@ -296,14 +306,13 @@ func (rs Receipts) Len() int { return len(rs) } func (rs Receipts) EncodeIndex(i int, w *bytes.Buffer) { r := rs[i] data := &receiptRLP{r.statusEncoding(), r.CumulativeGasUsed, r.Bloom, r.Logs} + if r.Type == LegacyTxType { + rlp.Encode(w, data) + return + } + w.WriteByte(r.Type) switch r.Type { - case LegacyTxType: - rlp.Encode(w, data) - case AccessListTxType: - w.WriteByte(AccessListTxType) - rlp.Encode(w, data) - case DynamicFeeTxType: - w.WriteByte(DynamicFeeTxType) + case AccessListTxType, DynamicFeeTxType, BlobTxType: rlp.Encode(w, data) default: // For unsupported types, write nothing. Since this is for @@ -314,7 +323,7 @@ func (rs Receipts) EncodeIndex(i int, w *bytes.Buffer) { // DeriveFields fills the receipts with their computed fields based on consensus // data and contextual infos like containing block and transactions. -func (rs Receipts) DeriveFields(config *params.ChainConfig, hash common.Hash, number uint64, time uint64, baseFee *big.Int, txs []*Transaction) error { +func (rs Receipts) DeriveFields(config *params.ChainConfig, hash common.Hash, number uint64, time uint64, baseFee *big.Int, blobGasPrice *big.Int, txs []*Transaction) error { signer := MakeSigner(config, new(big.Int).SetUint64(number), time) logIndex := uint(0) @@ -325,9 +334,14 @@ func (rs Receipts) DeriveFields(config *params.ChainConfig, hash common.Hash, nu // The transaction type and hash can be retrieved from the transaction itself rs[i].Type = txs[i].Type() rs[i].TxHash = txs[i].Hash() - rs[i].EffectiveGasPrice = txs[i].inner.effectiveGasPrice(new(big.Int), baseFee) + // EIP-4844 blob transaction fields + if txs[i].Type() == BlobTxType { + rs[i].BlobGasUsed = txs[i].BlobGas() + rs[i].BlobGasPrice = blobGasPrice + } + // block location fields rs[i].BlockHash = hash rs[i].BlockNumber = new(big.Int).SetUint64(number) diff --git a/core/types/receipt_test.go b/core/types/receipt_test.go index 168f36208b..a7b2644471 100644 --- a/core/types/receipt_test.go +++ b/core/types/receipt_test.go @@ -130,22 +130,24 @@ var ( }), // EIP-4844 transactions. NewTx(&BlobTx{ - To: &to6, + To: to6, Nonce: 6, Value: uint256.NewInt(6), Gas: 6, GasTipCap: uint256.NewInt(66), GasFeeCap: uint256.NewInt(1066), BlobFeeCap: uint256.NewInt(100066), + BlobHashes: []common.Hash{{}}, }), NewTx(&BlobTx{ - To: &to7, + To: to7, Nonce: 7, Value: uint256.NewInt(7), Gas: 7, GasTipCap: uint256.NewInt(77), GasFeeCap: uint256.NewInt(1077), BlobFeeCap: uint256.NewInt(100077), + BlobHashes: []common.Hash{{}, {}, {}}, }), } @@ -270,6 +272,8 @@ var ( TxHash: txs[5].Hash(), GasUsed: 6, EffectiveGasPrice: big.NewInt(1066), + BlobGasUsed: params.BlobTxBlobGasPerBlob, + BlobGasPrice: big.NewInt(920), BlockHash: blockHash, BlockNumber: blockNumber, TransactionIndex: 5, @@ -283,6 +287,8 @@ var ( TxHash: txs[6].Hash(), GasUsed: 7, EffectiveGasPrice: big.NewInt(1077), + BlobGasUsed: 3 * params.BlobTxBlobGasPerBlob, + BlobGasPrice: big.NewInt(920), BlockHash: blockHash, BlockNumber: blockNumber, TransactionIndex: 6, @@ -303,8 +309,9 @@ func TestDecodeEmptyTypedReceipt(t *testing.T) { func TestDeriveFields(t *testing.T) { // Re-derive receipts. basefee := big.NewInt(1000) + blobGasPrice := big.NewInt(920) derivedReceipts := clearComputedFieldsOnReceipts(receipts) - err := Receipts(derivedReceipts).DeriveFields(params.TestChainConfig, blockHash, blockNumber.Uint64(), blockTime, basefee, txs) + err := Receipts(derivedReceipts).DeriveFields(params.TestChainConfig, blockHash, blockNumber.Uint64(), blockTime, basefee, blobGasPrice, txs) if err != nil { t.Fatalf("DeriveFields(...) = %v, want ", err) } @@ -501,6 +508,9 @@ func clearComputedFieldsOnReceipt(receipt *Receipt) *Receipt { cpy.ContractAddress = common.Address{0xff, 0xff, 0x33} cpy.GasUsed = 0xffffffff cpy.Logs = clearComputedFieldsOnLogs(receipt.Logs) + cpy.EffectiveGasPrice = big.NewInt(0) + cpy.BlobGasUsed = 0 + cpy.BlobGasPrice = nil return &cpy } diff --git a/core/types/state_account.go b/core/types/state_account.go index 3b01be4519..314f4943ec 100644 --- a/core/types/state_account.go +++ b/core/types/state_account.go @@ -17,9 +17,11 @@ package types import ( + "bytes" "math/big" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/rlp" ) //go:generate go run ../../rlp/rlpgen -type StateAccount -out gen_account_rlp.go @@ -32,3 +34,88 @@ type StateAccount struct { Root common.Hash // merkle root of the storage trie CodeHash []byte } + +// NewEmptyStateAccount constructs an empty state account. +func NewEmptyStateAccount() *StateAccount { + return &StateAccount{ + Balance: new(big.Int), + Root: EmptyRootHash, + CodeHash: EmptyCodeHash.Bytes(), + } +} + +// Copy returns a deep-copied state account object. +func (acct *StateAccount) Copy() *StateAccount { + var balance *big.Int + if acct.Balance != nil { + balance = new(big.Int).Set(acct.Balance) + } + return &StateAccount{ + Nonce: acct.Nonce, + Balance: balance, + Root: acct.Root, + CodeHash: common.CopyBytes(acct.CodeHash), + } +} + +// SlimAccount is a modified version of an Account, where the root is replaced +// with a byte slice. This format can be used to represent full-consensus format +// or slim format which replaces the empty root and code hash as nil byte slice. +type SlimAccount struct { + Nonce uint64 + Balance *big.Int + Root []byte // Nil if root equals to types.EmptyRootHash + CodeHash []byte // Nil if hash equals to types.EmptyCodeHash +} + +// SlimAccountRLP encodes the state account in 'slim RLP' format. +func SlimAccountRLP(account StateAccount) []byte { + slim := SlimAccount{ + Nonce: account.Nonce, + Balance: account.Balance, + } + if account.Root != EmptyRootHash { + slim.Root = account.Root[:] + } + if !bytes.Equal(account.CodeHash, EmptyCodeHash[:]) { + slim.CodeHash = account.CodeHash + } + data, err := rlp.EncodeToBytes(slim) + if err != nil { + panic(err) + } + return data +} + +// FullAccount decodes the data on the 'slim RLP' format and return +// the consensus format account. +func FullAccount(data []byte) (*StateAccount, error) { + var slim SlimAccount + if err := rlp.DecodeBytes(data, &slim); err != nil { + return nil, err + } + var account StateAccount + account.Nonce, account.Balance = slim.Nonce, slim.Balance + + // Interpret the storage root and code hash in slim format. + if len(slim.Root) == 0 { + account.Root = EmptyRootHash + } else { + account.Root = common.BytesToHash(slim.Root) + } + if len(slim.CodeHash) == 0 { + account.CodeHash = EmptyCodeHash[:] + } else { + account.CodeHash = slim.CodeHash + } + return &account, nil +} + +// FullAccountRLP converts data on the 'slim RLP' format into the full RLP-format. +func FullAccountRLP(data []byte) ([]byte, error) { + account, err := FullAccount(data) + if err != nil { + return nil, err + } + return rlp.EncodeToBytes(account) +} diff --git a/core/types/transaction.go b/core/types/transaction.go index b7cb36b602..78a1b9ba64 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -18,7 +18,6 @@ package types import ( "bytes" - "container/heap" "errors" "io" "math/big" @@ -83,9 +82,6 @@ type TxData interface { value() *big.Int nonce() uint64 to() *common.Address - blobGas() uint64 - blobGasFeeCap() *big.Int - blobHashes() []common.Hash rawSignatureValues() (v, r, s *big.Int) setSignatureValues(chainID, v, r, s *big.Int) @@ -97,6 +93,9 @@ type TxData interface { // copy of the computed value, i.e. callers are allowed to mutate the result. // Method implementations can use 'dst' to store the result. effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int + + encode(*bytes.Buffer) error + decode([]byte) error } // EncodeRLP implements rlp.Encoder @@ -117,7 +116,7 @@ func (tx *Transaction) EncodeRLP(w io.Writer) error { // encodeTyped writes the canonical encoding of a typed transaction to w. func (tx *Transaction) encodeTyped(w *bytes.Buffer) error { w.WriteByte(tx.Type()) - return rlp.Encode(w, tx.inner) + return tx.inner.encode(w) } // MarshalBinary returns the canonical encoding of the transaction. @@ -146,15 +145,23 @@ func (tx *Transaction) DecodeRLP(s *rlp.Stream) error { tx.setDecoded(&inner, rlp.ListSize(size)) } return err + case kind == rlp.Byte: + return errShortTypedTx default: // It's an EIP-2718 typed TX envelope. - var b []byte - if b, err = s.Bytes(); err != nil { + // First read the tx 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 transaction. inner, err := tx.decodeTyped(b) if err == nil { - tx.setDecoded(inner, uint64(len(b))) + tx.setDecoded(inner, size) } return err } @@ -187,22 +194,19 @@ func (tx *Transaction) decodeTyped(b []byte) (TxData, error) { if len(b) <= 1 { return nil, errShortTypedTx } + var inner TxData switch b[0] { case AccessListTxType: - var inner AccessListTx - err := rlp.DecodeBytes(b[1:], &inner) - return &inner, err + inner = new(AccessListTx) case DynamicFeeTxType: - var inner DynamicFeeTx - err := rlp.DecodeBytes(b[1:], &inner) - return &inner, err + inner = new(DynamicFeeTx) case BlobTxType: - var inner BlobTx - err := rlp.DecodeBytes(b[1:], &inner) - return &inner, err + inner = new(BlobTx) default: return nil, ErrTxTypeNotSupported } + err := inner.decode(b[1:]) + return inner, err } // setDecoded sets the inner transaction and size after decoding. @@ -289,15 +293,6 @@ func (tx *Transaction) GasTipCap() *big.Int { return new(big.Int).Set(tx.inner.g // GasFeeCap returns the fee cap per gas of the transaction. func (tx *Transaction) GasFeeCap() *big.Int { return new(big.Int).Set(tx.inner.gasFeeCap()) } -// BlobGas returns the data gas limit of the transaction for blob transactions, 0 otherwise. -func (tx *Transaction) BlobGas() uint64 { return tx.inner.blobGas() } - -// BlobGasFeeCap returns the data gas fee cap per data gas of the transaction for blob transactions, nil otherwise. -func (tx *Transaction) BlobGasFeeCap() *big.Int { return tx.inner.blobGasFeeCap() } - -// BlobHashes returns the hases of the blob commitments for blob transactions, nil otherwise. -func (tx *Transaction) BlobHashes() []common.Hash { return tx.inner.blobHashes() } - // Value returns the ether amount of the transaction. func (tx *Transaction) Value() *big.Int { return new(big.Int).Set(tx.inner.value()) } @@ -384,14 +379,79 @@ func (tx *Transaction) EffectiveGasTipIntCmp(other *big.Int, baseFee *big.Int) i return tx.EffectiveGasTipValue(baseFee).Cmp(other) } +// BlobGas returns the blob gas limit of the transaction for blob transactions, 0 otherwise. +func (tx *Transaction) BlobGas() uint64 { + if blobtx, ok := tx.inner.(*BlobTx); ok { + return blobtx.blobGas() + } + return 0 +} + +// BlobGasFeeCap returns the blob gas fee cap per blob gas of the transaction for blob transactions, nil otherwise. +func (tx *Transaction) BlobGasFeeCap() *big.Int { + if blobtx, ok := tx.inner.(*BlobTx); ok { + return blobtx.BlobFeeCap.ToBig() + } + return nil +} + +// BlobHashes returns the hases of the blob commitments for blob transactions, nil otherwise. +func (tx *Transaction) BlobHashes() []common.Hash { + if blobtx, ok := tx.inner.(*BlobTx); ok { + return blobtx.BlobHashes + } + return nil +} + +// BlobTxSidecar returns the sidecar of a blob transaction, nil otherwise. +func (tx *Transaction) BlobTxSidecar() *BlobTxSidecar { + if blobtx, ok := tx.inner.(*BlobTx); ok { + return blobtx.Sidecar + } + return nil +} + // BlobGasFeeCapCmp compares the blob fee cap of two transactions. func (tx *Transaction) BlobGasFeeCapCmp(other *Transaction) int { - return tx.inner.blobGasFeeCap().Cmp(other.inner.blobGasFeeCap()) + return tx.BlobGasFeeCap().Cmp(other.BlobGasFeeCap()) } // BlobGasFeeCapIntCmp compares the blob fee cap of the transaction against the given blob fee cap. func (tx *Transaction) BlobGasFeeCapIntCmp(other *big.Int) int { - return tx.inner.blobGasFeeCap().Cmp(other) + return tx.BlobGasFeeCap().Cmp(other) +} + +// WithoutBlobTxSidecar returns a copy of tx with the blob sidecar removed. +func (tx *Transaction) WithoutBlobTxSidecar() *Transaction { + blobtx, ok := tx.inner.(*BlobTx) + if !ok { + return tx + } + cpy := &Transaction{ + inner: blobtx.withoutSidecar(), + 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. +func (tx *Transaction) SetTime(t time.Time) { + tx.time = t +} + +// Time returns the time when the transaction was first seen on the network. It +// is a heuristic to prefer mining older txs vs new all other things equal. +func (tx *Transaction) Time() time.Time { + return tx.time } // Hash returns the transaction hash. @@ -416,13 +476,24 @@ func (tx *Transaction) Size() uint64 { if size := tx.size.Load(); size != nil { return size.(uint64) } + + // Cache miss, encode and cache. + // Note we rely on the assumption that all tx.inner values are RLP-encoded! c := writeCounter(0) rlp.Encode(&c, &tx.inner) - size := uint64(c) - if tx.Type() != LegacyTxType { - size += 1 // type byte + + // For blob transactions, add the size of the blob content and the outer list of the + // tx + sidecar encoding. + if sc := tx.BlobTxSidecar(); sc != nil { + size += rlp.ListSize(sc.encodedSize()) } + + // For typed transactions, the encoding also includes the leading type byte. + if tx.Type() != LegacyTxType { + size += 1 + } + tx.size.Store(size) return size } @@ -502,123 +573,6 @@ func (s TxByNonce) Len() int { return len(s) } func (s TxByNonce) Less(i, j int) bool { return s[i].Nonce() < s[j].Nonce() } func (s TxByNonce) Swap(i, j int) { s[i], s[j] = s[j], s[i] } -// TxWithMinerFee wraps a transaction with its gas price or effective miner gasTipCap -type TxWithMinerFee struct { - tx *Transaction - minerFee *big.Int -} - -// NewTxWithMinerFee creates a wrapped transaction, calculating the effective -// miner gasTipCap if a base fee is provided. -// Returns error in case of a negative effective miner gasTipCap. -func NewTxWithMinerFee(tx *Transaction, baseFee *big.Int) (*TxWithMinerFee, error) { - minerFee, err := tx.EffectiveGasTip(baseFee) - if err != nil { - return nil, err - } - return &TxWithMinerFee{ - tx: tx, - minerFee: minerFee, - }, nil -} - -// TxByPriceAndTime implements both the sort and the heap interface, making it useful -// for all at once sorting as well as individually adding and removing elements. -type TxByPriceAndTime []*TxWithMinerFee - -func (s TxByPriceAndTime) Len() int { return len(s) } -func (s TxByPriceAndTime) Less(i, j int) bool { - // If the prices are equal, use the time the transaction was first seen for - // deterministic sorting - cmp := s[i].minerFee.Cmp(s[j].minerFee) - if cmp == 0 { - return s[i].tx.time.Before(s[j].tx.time) - } - return cmp > 0 -} -func (s TxByPriceAndTime) Swap(i, j int) { s[i], s[j] = s[j], s[i] } - -func (s *TxByPriceAndTime) Push(x interface{}) { - *s = append(*s, x.(*TxWithMinerFee)) -} - -func (s *TxByPriceAndTime) Pop() interface{} { - old := *s - n := len(old) - x := old[n-1] - old[n-1] = nil - *s = old[0 : n-1] - return x -} - -// TransactionsByPriceAndNonce represents a set of transactions that can return -// transactions in a profit-maximizing sorted order, while supporting removing -// entire batches of transactions for non-executable accounts. -type TransactionsByPriceAndNonce struct { - txs map[common.Address]Transactions // Per account nonce-sorted list of transactions - heads TxByPriceAndTime // Next transaction for each unique account (price heap) - signer Signer // Signer for the set of transactions - baseFee *big.Int // Current base fee -} - -// NewTransactionsByPriceAndNonce creates a transaction set that can retrieve -// price sorted transactions in a nonce-honouring way. -// -// Note, the input map is reowned so the caller should not interact any more with -// if after providing it to the constructor. -func NewTransactionsByPriceAndNonce(signer Signer, txs map[common.Address]Transactions, baseFee *big.Int) *TransactionsByPriceAndNonce { - // Initialize a price and received time based heap with the head transactions - heads := make(TxByPriceAndTime, 0, len(txs)) - for from, accTxs := range txs { - acc, _ := Sender(signer, accTxs[0]) - wrapped, err := NewTxWithMinerFee(accTxs[0], baseFee) - // Remove transaction if sender doesn't match from, or if wrapping fails. - if acc != from || err != nil { - delete(txs, from) - continue - } - heads = append(heads, wrapped) - txs[from] = accTxs[1:] - } - heap.Init(&heads) - - // Assemble and return the transaction set - return &TransactionsByPriceAndNonce{ - txs: txs, - heads: heads, - signer: signer, - baseFee: baseFee, - } -} - -// Peek returns the next transaction by price. -func (t *TransactionsByPriceAndNonce) Peek() *Transaction { - if len(t.heads) == 0 { - return nil - } - return t.heads[0].tx -} - -// Shift replaces the current best head with the next one from the same account. -func (t *TransactionsByPriceAndNonce) Shift() { - acc, _ := Sender(t.signer, t.heads[0].tx) - if txs, ok := t.txs[acc]; ok && len(txs) > 0 { - if wrapped, err := NewTxWithMinerFee(txs[0], t.baseFee); err == nil { - t.heads[0], t.txs[acc] = wrapped, txs[1:] - heap.Fix(&t.heads, 0) - return - } - } - heap.Pop(&t.heads) -} - -// Pop removes the best transaction, *not* replacing it with the next one from -// the same account. This should be used when a transaction cannot be executed -// and hence all subsequent ones should be discarded from the same account. -func (t *TransactionsByPriceAndNonce) Pop() { - heap.Pop(&t.heads) -} - // copyAddressPtr copies an address. func copyAddressPtr(a *common.Address) *common.Address { if a == nil { diff --git a/core/types/transaction_marshalling.go b/core/types/transaction_marshalling.go index 6c6c50d498..e5d71a85d6 100644 --- a/core/types/transaction_marshalling.go +++ b/core/types/transaction_marshalling.go @@ -37,7 +37,7 @@ type txJSON struct { GasPrice *hexutil.Big `json:"gasPrice"` MaxPriorityFeePerGas *hexutil.Big `json:"maxPriorityFeePerGas"` MaxFeePerGas *hexutil.Big `json:"maxFeePerGas"` - MaxFeePerDataGas *hexutil.Big `json:"maxFeePerDataGas,omitempty"` + MaxFeePerBlobGas *hexutil.Big `json:"maxFeePerBlobGas,omitempty"` Value *hexutil.Big `json:"value"` Input *hexutil.Bytes `json:"input"` AccessList *AccessList `json:"accessList,omitempty"` @@ -45,11 +45,32 @@ type txJSON struct { V *hexutil.Big `json:"v"` R *hexutil.Big `json:"r"` S *hexutil.Big `json:"s"` + YParity *hexutil.Uint64 `json:"yParity,omitempty"` // Only used for encoding: Hash common.Hash `json:"hash"` } +// yParityValue returns the YParity value from JSON. For backwards-compatibility reasons, +// this can be given in the 'v' field or the 'yParity' field. If both exist, they must match. +func (tx *txJSON) yParityValue() (*big.Int, error) { + if tx.YParity != nil { + val := uint64(*tx.YParity) + if val != 0 && val != 1 { + return nil, errors.New("'yParity' field must be 0 or 1") + } + bigval := new(big.Int).SetUint64(val) + if tx.V != nil && tx.V.ToInt().Cmp(bigval) != 0 { + return nil, errors.New("'v' and 'yParity' fields do not match") + } + return bigval, nil + } + if tx.V != nil { + return tx.V.ToInt(), nil + } + return nil, errors.New("missing 'yParity' or 'v' field in transaction") +} + // MarshalJSON marshals as JSON with a hash. func (tx *Transaction) MarshalJSON() ([]byte, error) { var enc txJSON @@ -69,6 +90,9 @@ func (tx *Transaction) MarshalJSON() ([]byte, error) { enc.V = (*hexutil.Big)(itx.V) enc.R = (*hexutil.Big)(itx.R) enc.S = (*hexutil.Big)(itx.S) + if tx.Protected() { + enc.ChainID = (*hexutil.Big)(tx.ChainId()) + } case *AccessListTx: enc.ChainID = (*hexutil.Big)(itx.ChainID) @@ -82,6 +106,8 @@ func (tx *Transaction) MarshalJSON() ([]byte, error) { enc.V = (*hexutil.Big)(itx.V) enc.R = (*hexutil.Big)(itx.R) enc.S = (*hexutil.Big)(itx.S) + yparity := itx.V.Uint64() + enc.YParity = (*hexutil.Uint64)(&yparity) case *DynamicFeeTx: enc.ChainID = (*hexutil.Big)(itx.ChainID) @@ -96,6 +122,8 @@ func (tx *Transaction) MarshalJSON() ([]byte, error) { enc.V = (*hexutil.Big)(itx.V) enc.R = (*hexutil.Big)(itx.R) enc.S = (*hexutil.Big)(itx.S) + yparity := itx.V.Uint64() + enc.YParity = (*hexutil.Uint64)(&yparity) case *BlobTx: enc.ChainID = (*hexutil.Big)(itx.ChainID.ToBig()) @@ -103,7 +131,7 @@ func (tx *Transaction) MarshalJSON() ([]byte, error) { enc.Gas = (*hexutil.Uint64)(&itx.Gas) enc.MaxFeePerGas = (*hexutil.Big)(itx.GasFeeCap.ToBig()) enc.MaxPriorityFeePerGas = (*hexutil.Big)(itx.GasTipCap.ToBig()) - enc.MaxFeePerDataGas = (*hexutil.Big)(itx.BlobFeeCap.ToBig()) + enc.MaxFeePerBlobGas = (*hexutil.Big)(itx.BlobFeeCap.ToBig()) enc.Value = (*hexutil.Big)(itx.Value.ToBig()) enc.Input = (*hexutil.Bytes)(&itx.Data) enc.AccessList = &itx.AccessList @@ -112,6 +140,8 @@ func (tx *Transaction) MarshalJSON() ([]byte, error) { enc.V = (*hexutil.Big)(itx.V.ToBig()) enc.R = (*hexutil.Big)(itx.R.ToBig()) enc.S = (*hexutil.Big)(itx.S.ToBig()) + yparity := itx.V.Uint64() + enc.YParity = (*hexutil.Uint64)(&yparity) } return json.Marshal(&enc) } @@ -119,7 +149,8 @@ func (tx *Transaction) MarshalJSON() ([]byte, error) { // UnmarshalJSON unmarshals from JSON. func (tx *Transaction) UnmarshalJSON(input []byte) error { var dec txJSON - if err := json.Unmarshal(input, &dec); err != nil { + err := json.Unmarshal(input, &dec) + if err != nil { return err } @@ -152,20 +183,23 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error { return errors.New("missing required field 'input' in transaction") } itx.Data = *dec.Input - if dec.V == nil { - return errors.New("missing required field 'v' in transaction") - } - itx.V = (*big.Int)(dec.V) + + // signature R if dec.R == nil { return errors.New("missing required field 'r' in transaction") } itx.R = (*big.Int)(dec.R) + // signature S if dec.S == nil { return errors.New("missing required field 's' in transaction") } itx.S = (*big.Int)(dec.S) - withSignature := itx.V.Sign() != 0 || itx.R.Sign() != 0 || itx.S.Sign() != 0 - if withSignature { + // signature V + if dec.V == nil { + return errors.New("missing required field 'v' in transaction") + } + itx.V = (*big.Int)(dec.V) + if itx.V.Sign() != 0 || itx.R.Sign() != 0 || itx.S.Sign() != 0 { if err := sanityCheckSignature(itx.V, itx.R, itx.S, true); err != nil { return err } @@ -201,23 +235,26 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error { return errors.New("missing required field 'input' in transaction") } itx.Data = *dec.Input - if dec.V == nil { - return errors.New("missing required field 'v' in transaction") - } if dec.AccessList != nil { itx.AccessList = *dec.AccessList } - itx.V = (*big.Int)(dec.V) + + // signature R if dec.R == nil { return errors.New("missing required field 'r' in transaction") } itx.R = (*big.Int)(dec.R) + // signature S if dec.S == nil { return errors.New("missing required field 's' in transaction") } itx.S = (*big.Int)(dec.S) - withSignature := itx.V.Sign() != 0 || itx.R.Sign() != 0 || itx.S.Sign() != 0 - if withSignature { + // signature V + itx.V, err = dec.yParityValue() + if err != nil { + return err + } + if itx.V.Sign() != 0 || itx.R.Sign() != 0 || itx.S.Sign() != 0 { if err := sanityCheckSignature(itx.V, itx.R, itx.S, false); err != nil { return err } @@ -263,17 +300,23 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error { if dec.AccessList != nil { itx.AccessList = *dec.AccessList } - itx.V = (*big.Int)(dec.V) + + // signature R if dec.R == nil { return errors.New("missing required field 'r' in transaction") } itx.R = (*big.Int)(dec.R) + // signature S if dec.S == nil { return errors.New("missing required field 's' in transaction") } itx.S = (*big.Int)(dec.S) - withSignature := itx.V.Sign() != 0 || itx.R.Sign() != 0 || itx.S.Sign() != 0 - if withSignature { + // signature V + itx.V, err = dec.yParityValue() + if err != nil { + return err + } + if itx.V.Sign() != 0 || itx.R.Sign() != 0 || itx.S.Sign() != 0 { if err := sanityCheckSignature(itx.V, itx.R, itx.S, false); err != nil { return err } @@ -290,9 +333,10 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error { return errors.New("missing required field 'nonce' in transaction") } itx.Nonce = uint64(*dec.Nonce) - if dec.To != nil { - itx.To = dec.To + if dec.To == nil { + return errors.New("missing required field 'to' in transaction") } + itx.To = *dec.To if dec.Gas == nil { return errors.New("missing required field 'gas' for txdata") } @@ -305,10 +349,10 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error { return errors.New("missing required field 'maxFeePerGas' for txdata") } itx.GasFeeCap = uint256.MustFromBig((*big.Int)(dec.MaxFeePerGas)) - if dec.MaxFeePerDataGas == nil { - return errors.New("missing required field 'maxFeePerDataGas' for txdata") + if dec.MaxFeePerBlobGas == nil { + return errors.New("missing required field 'maxFeePerBlobGas' for txdata") } - itx.BlobFeeCap = uint256.MustFromBig((*big.Int)(dec.MaxFeePerDataGas)) + itx.BlobFeeCap = uint256.MustFromBig((*big.Int)(dec.MaxFeePerBlobGas)) if dec.Value == nil { return errors.New("missing required field 'value' in transaction") } @@ -327,18 +371,35 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error { return errors.New("missing required field 'blobVersionedHashes' in transaction") } itx.BlobHashes = dec.BlobVersionedHashes - itx.V = uint256.MustFromBig((*big.Int)(dec.V)) + + // signature R + var overflow bool if dec.R == nil { return errors.New("missing required field 'r' in transaction") } - itx.R = uint256.MustFromBig((*big.Int)(dec.R)) + itx.R, overflow = uint256.FromBig((*big.Int)(dec.R)) + if overflow { + return errors.New("'r' value overflows uint256") + } + // signature S if dec.S == nil { return errors.New("missing required field 's' in transaction") } - itx.S = uint256.MustFromBig((*big.Int)(dec.S)) - withSignature := itx.V.Sign() != 0 || itx.R.Sign() != 0 || itx.S.Sign() != 0 - if withSignature { - if err := sanityCheckSignature(itx.V.ToBig(), itx.R.ToBig(), itx.S.ToBig(), false); err != nil { + itx.S, overflow = uint256.FromBig((*big.Int)(dec.S)) + if overflow { + return errors.New("'s' value overflows uint256") + } + // signature V + vbig, err := dec.yParityValue() + if err != nil { + return err + } + itx.V, overflow = uint256.FromBig(vbig) + if overflow { + return errors.New("'v' value overflows uint256") + } + if itx.V.Sign() != 0 || itx.R.Sign() != 0 || itx.S.Sign() != 0 { + if err := sanityCheckSignature(vbig, itx.R.ToBig(), itx.S.ToBig(), false); err != nil { return err } } diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go index d7c162898c..cd57effcb1 100644 --- a/core/types/transaction_signing.go +++ b/core/types/transaction_signing.go @@ -40,7 +40,7 @@ type sigCache struct { func MakeSigner(config *params.ChainConfig, blockNumber *big.Int, blockTime uint64) Signer { var signer Signer switch { - case config.IsCancun(blockTime): + case config.IsCancun(blockNumber, blockTime): signer = NewCancunSigner(config.ChainID) case config.IsLondon(blockNumber): signer = NewLondonSigner(config.ChainID) @@ -57,9 +57,9 @@ func MakeSigner(config *params.ChainConfig, blockNumber *big.Int, blockTime uint } // LatestSigner returns the 'most permissive' Signer available for the given chain -// configuration. Specifically, this enables support of EIP-155 replay protection and -// EIP-2930 access list transactions when their respective forks are scheduled to occur at -// any block number in the chain config. +// configuration. Specifically, this enables support of all types of transacrions +// when their respective forks are scheduled to occur at any block number (or time) +// in the chain config. // // Use this in transaction-handling code where the current block number is unknown. If you // have the current block number available, use MakeSigner instead. @@ -331,11 +331,7 @@ func (s eip2930Signer) Sender(tx *Transaction) (common.Address, error) { V, R, S := tx.RawSignatureValues() switch tx.Type() { case LegacyTxType: - if !tx.Protected() { - return HomesteadSigner{}.Sender(tx) - } - V = new(big.Int).Sub(V, s.chainIdMul) - V.Sub(V, big8) + return s.EIP155Signer.Sender(tx) case AccessListTxType: // AL txs are defined to use 0 and 1 as their recovery // id, add 27 to become equivalent to unprotected Homestead signatures. @@ -372,15 +368,7 @@ func (s eip2930Signer) SignatureValues(tx *Transaction, sig []byte) (R, S, V *bi func (s eip2930Signer) Hash(tx *Transaction) common.Hash { switch tx.Type() { case LegacyTxType: - return rlpHash([]interface{}{ - tx.Nonce(), - tx.GasPrice(), - tx.Gas(), - tx.To(), - tx.Value(), - tx.Data(), - s.chainId, uint(0), uint(0), - }) + return s.EIP155Signer.Hash(tx) case AccessListTxType: return prefixedRlpHash( tx.Type(), diff --git a/core/types/transaction_test.go b/core/types/transaction_test.go index 4b96c6b91a..25ced0841b 100644 --- a/core/types/transaction_test.go +++ b/core/types/transaction_test.go @@ -23,10 +23,8 @@ import ( "errors" "fmt" "math/big" - "math/rand" "reflect" "testing" - "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" @@ -216,7 +214,7 @@ func TestEIP2718TransactionEncode(t *testing.T) { func decodeTx(data []byte) (*Transaction, error) { var tx Transaction - t, err := &tx, rlp.Decode(bytes.NewReader(data), &tx) + t, err := &tx, rlp.DecodeBytes(data, &tx) return t, err } @@ -259,152 +257,6 @@ func TestRecipientNormal(t *testing.T) { } } -func TestTransactionPriceNonceSortLegacy(t *testing.T) { - testTransactionPriceNonceSort(t, nil) -} - -func TestTransactionPriceNonceSort1559(t *testing.T) { - testTransactionPriceNonceSort(t, big.NewInt(0)) - testTransactionPriceNonceSort(t, big.NewInt(5)) - testTransactionPriceNonceSort(t, big.NewInt(50)) -} - -// Tests that transactions can be correctly sorted according to their price in -// decreasing order, but at the same time with increasing nonces when issued by -// the same account. -func testTransactionPriceNonceSort(t *testing.T, baseFee *big.Int) { - // Generate a batch of accounts to start with - keys := make([]*ecdsa.PrivateKey, 25) - for i := 0; i < len(keys); i++ { - keys[i], _ = crypto.GenerateKey() - } - signer := LatestSignerForChainID(common.Big1) - - // Generate a batch of transactions with overlapping values, but shifted nonces - groups := map[common.Address]Transactions{} - expectedCount := 0 - for start, key := range keys { - addr := crypto.PubkeyToAddress(key.PublicKey) - count := 25 - for i := 0; i < 25; i++ { - var tx *Transaction - gasFeeCap := rand.Intn(50) - if baseFee == nil { - tx = NewTx(&LegacyTx{ - Nonce: uint64(start + i), - To: &common.Address{}, - Value: big.NewInt(100), - Gas: 100, - GasPrice: big.NewInt(int64(gasFeeCap)), - Data: nil, - }) - } else { - tx = NewTx(&DynamicFeeTx{ - Nonce: uint64(start + i), - To: &common.Address{}, - Value: big.NewInt(100), - Gas: 100, - GasFeeCap: big.NewInt(int64(gasFeeCap)), - GasTipCap: big.NewInt(int64(rand.Intn(gasFeeCap + 1))), - Data: nil, - }) - if count == 25 && int64(gasFeeCap) < baseFee.Int64() { - count = i - } - } - tx, err := SignTx(tx, signer, key) - if err != nil { - t.Fatalf("failed to sign tx: %s", err) - } - groups[addr] = append(groups[addr], tx) - } - expectedCount += count - } - // Sort the transactions and cross check the nonce ordering - txset := NewTransactionsByPriceAndNonce(signer, groups, baseFee) - - txs := Transactions{} - for tx := txset.Peek(); tx != nil; tx = txset.Peek() { - txs = append(txs, tx) - txset.Shift() - } - if len(txs) != expectedCount { - t.Errorf("expected %d transactions, found %d", expectedCount, len(txs)) - } - for i, txi := range txs { - fromi, _ := Sender(signer, txi) - - // Make sure the nonce order is valid - for j, txj := range txs[i+1:] { - fromj, _ := Sender(signer, txj) - if fromi == fromj && txi.Nonce() > txj.Nonce() { - t.Errorf("invalid nonce ordering: tx #%d (A=%x N=%v) < tx #%d (A=%x N=%v)", i, fromi[:4], txi.Nonce(), i+j, fromj[:4], txj.Nonce()) - } - } - // If the next tx has different from account, the price must be lower than the current one - if i+1 < len(txs) { - next := txs[i+1] - fromNext, _ := Sender(signer, next) - tip, err := txi.EffectiveGasTip(baseFee) - nextTip, nextErr := next.EffectiveGasTip(baseFee) - if err != nil || nextErr != nil { - t.Errorf("error calculating effective tip") - } - if fromi != fromNext && tip.Cmp(nextTip) < 0 { - t.Errorf("invalid gasprice ordering: tx #%d (A=%x P=%v) < tx #%d (A=%x P=%v)", i, fromi[:4], txi.GasPrice(), i+1, fromNext[:4], next.GasPrice()) - } - } - } -} - -// Tests that if multiple transactions have the same price, the ones seen earlier -// are prioritized to avoid network spam attacks aiming for a specific ordering. -func TestTransactionTimeSort(t *testing.T) { - // Generate a batch of accounts to start with - keys := make([]*ecdsa.PrivateKey, 5) - for i := 0; i < len(keys); i++ { - keys[i], _ = crypto.GenerateKey() - } - signer := HomesteadSigner{} - - // Generate a batch of transactions with overlapping prices, but different creation times - groups := map[common.Address]Transactions{} - for start, key := range keys { - addr := crypto.PubkeyToAddress(key.PublicKey) - - tx, _ := SignTx(NewTransaction(0, common.Address{}, big.NewInt(100), 100, big.NewInt(1), nil), signer, key) - tx.time = time.Unix(0, int64(len(keys)-start)) - - groups[addr] = append(groups[addr], tx) - } - // Sort the transactions and cross check the nonce ordering - txset := NewTransactionsByPriceAndNonce(signer, groups, nil) - - txs := Transactions{} - for tx := txset.Peek(); tx != nil; tx = txset.Peek() { - txs = append(txs, tx) - txset.Shift() - } - if len(txs) != len(keys) { - t.Errorf("expected %d transactions, found %d", len(keys), len(txs)) - } - for i, txi := range txs { - fromi, _ := Sender(signer, txi) - if i+1 < len(txs) { - next := txs[i+1] - fromNext, _ := Sender(signer, next) - - if txi.GasPrice().Cmp(next.GasPrice()) < 0 { - t.Errorf("invalid gasprice ordering: tx #%d (A=%x P=%v) < tx #%d (A=%x P=%v)", i, fromi[:4], txi.GasPrice(), i+1, fromNext[:4], next.GasPrice()) - } - // Make sure time order is ascending if the txs have the same gas price - if txi.GasPrice().Cmp(next.GasPrice()) == 0 && txi.time.After(next.time) { - t.Errorf("invalid received time ordering: tx #%d (A=%x T=%v) > tx #%d (A=%x T=%v)", i, fromi[:4], txi.time, i+1, fromNext[:4], next.time) - } - } - } -} - // TestTransactionCoding tests serializing/de-serializing to/from rlp and JSON. func TestTransactionCoding(t *testing.T) { key, err := crypto.GenerateKey() @@ -526,7 +378,7 @@ func assertEqual(orig *Transaction, cpy *Transaction) error { } if orig.AccessList() != nil { if !reflect.DeepEqual(orig.AccessList(), cpy.AccessList()) { - return fmt.Errorf("access list wrong!") + return errors.New("access list wrong!") } } return nil diff --git a/core/types/tx_access_list.go b/core/types/tx_access_list.go index 7ce9da73ec..730a77b752 100644 --- a/core/types/tx_access_list.go +++ b/core/types/tx_access_list.go @@ -17,9 +17,11 @@ package types import ( + "bytes" "math/big" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/rlp" ) //go:generate go run github.com/fjl/gencodec -type AccessTuple -out gen_access_tuple.go @@ -94,20 +96,17 @@ func (tx *AccessListTx) copy() TxData { } // accessors for innerTx. -func (tx *AccessListTx) txType() byte { return AccessListTxType } -func (tx *AccessListTx) chainID() *big.Int { return tx.ChainID } -func (tx *AccessListTx) accessList() AccessList { return tx.AccessList } -func (tx *AccessListTx) data() []byte { return tx.Data } -func (tx *AccessListTx) gas() uint64 { return tx.Gas } -func (tx *AccessListTx) gasPrice() *big.Int { return tx.GasPrice } -func (tx *AccessListTx) gasTipCap() *big.Int { return tx.GasPrice } -func (tx *AccessListTx) gasFeeCap() *big.Int { return tx.GasPrice } -func (tx *AccessListTx) value() *big.Int { return tx.Value } -func (tx *AccessListTx) nonce() uint64 { return tx.Nonce } -func (tx *AccessListTx) to() *common.Address { return tx.To } -func (tx *AccessListTx) blobGas() uint64 { return 0 } -func (tx *AccessListTx) blobGasFeeCap() *big.Int { return nil } -func (tx *AccessListTx) blobHashes() []common.Hash { return nil } +func (tx *AccessListTx) txType() byte { return AccessListTxType } +func (tx *AccessListTx) chainID() *big.Int { return tx.ChainID } +func (tx *AccessListTx) accessList() AccessList { return tx.AccessList } +func (tx *AccessListTx) data() []byte { return tx.Data } +func (tx *AccessListTx) gas() uint64 { return tx.Gas } +func (tx *AccessListTx) gasPrice() *big.Int { return tx.GasPrice } +func (tx *AccessListTx) gasTipCap() *big.Int { return tx.GasPrice } +func (tx *AccessListTx) gasFeeCap() *big.Int { return tx.GasPrice } +func (tx *AccessListTx) value() *big.Int { return tx.Value } +func (tx *AccessListTx) nonce() uint64 { return tx.Nonce } +func (tx *AccessListTx) to() *common.Address { return tx.To } func (tx *AccessListTx) effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int { return dst.Set(tx.GasPrice) @@ -120,3 +119,11 @@ func (tx *AccessListTx) rawSignatureValues() (v, r, s *big.Int) { func (tx *AccessListTx) setSignatureValues(chainID, v, r, s *big.Int) { tx.ChainID, tx.V, tx.R, tx.S = chainID, v, r, s } + +func (tx *AccessListTx) encode(b *bytes.Buffer) error { + return rlp.Encode(b, tx) +} + +func (tx *AccessListTx) decode(input []byte) error { + return rlp.DecodeBytes(input, tx) +} diff --git a/core/types/tx_blob.go b/core/types/tx_blob.go index 58065d0017..da4a9b72f1 100644 --- a/core/types/tx_blob.go +++ b/core/types/tx_blob.go @@ -17,10 +17,14 @@ package types import ( + "bytes" + "crypto/sha256" "math/big" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto/kzg4844" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rlp" "github.com/holiman/uint256" ) @@ -31,24 +35,68 @@ type BlobTx struct { GasTipCap *uint256.Int // a.k.a. maxPriorityFeePerGas GasFeeCap *uint256.Int // a.k.a. maxFeePerGas Gas uint64 - To *common.Address `rlp:"nil"` // nil means contract creation + To common.Address Value *uint256.Int Data []byte AccessList AccessList - BlobFeeCap *uint256.Int // a.k.a. maxFeePerDataGas + BlobFeeCap *uint256.Int // a.k.a. maxFeePerBlobGas BlobHashes []common.Hash + // A blob transaction can optionally contain blobs. This field must be set when BlobTx + // is used to create a transaction for sigining. + Sidecar *BlobTxSidecar `rlp:"-"` + // Signature values V *uint256.Int `json:"v" gencodec:"required"` R *uint256.Int `json:"r" gencodec:"required"` S *uint256.Int `json:"s" gencodec:"required"` } +// BlobTxSidecar contains the blobs of a blob transaction. +type BlobTxSidecar struct { + Blobs []kzg4844.Blob // Blobs needed by the blob pool + Commitments []kzg4844.Commitment // Commitments needed by the blob pool + Proofs []kzg4844.Proof // Proofs needed by the blob pool +} + +// BlobHashes computes the blob hashes of the given blobs. +func (sc *BlobTxSidecar) BlobHashes() []common.Hash { + h := make([]common.Hash, len(sc.Commitments)) + for i := range sc.Blobs { + h[i] = blobHash(&sc.Commitments[i]) + } + return h +} + +// encodedSize computes the RLP size of the sidecar elements. This does NOT return the +// encoded size of the BlobTxSidecar, it's just a helper for tx.Size(). +func (sc *BlobTxSidecar) encodedSize() uint64 { + var blobs, commitments, proofs uint64 + for i := range sc.Blobs { + blobs += rlp.BytesSize(sc.Blobs[i][:]) + } + for i := range sc.Commitments { + commitments += rlp.BytesSize(sc.Commitments[i][:]) + } + for i := range sc.Proofs { + proofs += rlp.BytesSize(sc.Proofs[i][:]) + } + return rlp.ListSize(blobs) + rlp.ListSize(commitments) + rlp.ListSize(proofs) +} + +// blobTxWithBlobs is used for encoding of transactions when blobs are present. +type blobTxWithBlobs struct { + BlobTx *BlobTx + Blobs []kzg4844.Blob + Commitments []kzg4844.Commitment + Proofs []kzg4844.Proof +} + // copy creates a deep copy of the transaction data and initializes all fields. func (tx *BlobTx) copy() TxData { cpy := &BlobTx{ Nonce: tx.Nonce, - To: copyAddressPtr(tx.To), + To: tx.To, Data: common.CopyBytes(tx.Data), Gas: tx.Gas, // These are copied below. @@ -90,24 +138,29 @@ func (tx *BlobTx) copy() TxData { if tx.S != nil { cpy.S.Set(tx.S) } + if tx.Sidecar != nil { + cpy.Sidecar = &BlobTxSidecar{ + Blobs: append([]kzg4844.Blob(nil), tx.Sidecar.Blobs...), + Commitments: append([]kzg4844.Commitment(nil), tx.Sidecar.Commitments...), + Proofs: append([]kzg4844.Proof(nil), tx.Sidecar.Proofs...), + } + } return cpy } // accessors for innerTx. -func (tx *BlobTx) txType() byte { return BlobTxType } -func (tx *BlobTx) chainID() *big.Int { return tx.ChainID.ToBig() } -func (tx *BlobTx) accessList() AccessList { return tx.AccessList } -func (tx *BlobTx) data() []byte { return tx.Data } -func (tx *BlobTx) gas() uint64 { return tx.Gas } -func (tx *BlobTx) gasFeeCap() *big.Int { return tx.GasFeeCap.ToBig() } -func (tx *BlobTx) gasTipCap() *big.Int { return tx.GasTipCap.ToBig() } -func (tx *BlobTx) gasPrice() *big.Int { return tx.GasFeeCap.ToBig() } -func (tx *BlobTx) value() *big.Int { return tx.Value.ToBig() } -func (tx *BlobTx) nonce() uint64 { return tx.Nonce } -func (tx *BlobTx) to() *common.Address { return tx.To } -func (tx *BlobTx) blobGas() uint64 { return params.BlobTxDataGasPerBlob * uint64(len(tx.BlobHashes)) } -func (tx *BlobTx) blobGasFeeCap() *big.Int { return tx.BlobFeeCap.ToBig() } -func (tx *BlobTx) blobHashes() []common.Hash { return tx.BlobHashes } +func (tx *BlobTx) txType() byte { return BlobTxType } +func (tx *BlobTx) chainID() *big.Int { return tx.ChainID.ToBig() } +func (tx *BlobTx) accessList() AccessList { return tx.AccessList } +func (tx *BlobTx) data() []byte { return tx.Data } +func (tx *BlobTx) gas() uint64 { return tx.Gas } +func (tx *BlobTx) gasFeeCap() *big.Int { return tx.GasFeeCap.ToBig() } +func (tx *BlobTx) gasTipCap() *big.Int { return tx.GasTipCap.ToBig() } +func (tx *BlobTx) gasPrice() *big.Int { return tx.GasFeeCap.ToBig() } +func (tx *BlobTx) value() *big.Int { return tx.Value.ToBig() } +func (tx *BlobTx) nonce() uint64 { return tx.Nonce } +func (tx *BlobTx) to() *common.Address { tmp := tx.To; return &tmp } +func (tx *BlobTx) blobGas() uint64 { return params.BlobTxBlobGasPerBlob * uint64(len(tx.BlobHashes)) } func (tx *BlobTx) effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int { if baseFee == nil { @@ -130,3 +183,64 @@ func (tx *BlobTx) setSignatureValues(chainID, v, r, s *big.Int) { tx.R.SetFromBig(r) tx.S.SetFromBig(s) } + +func (tx *BlobTx) withoutSidecar() *BlobTx { + cpy := *tx + cpy.Sidecar = nil + return &cpy +} + +func (tx *BlobTx) encode(b *bytes.Buffer) error { + if tx.Sidecar == nil { + return rlp.Encode(b, tx) + } + inner := &blobTxWithBlobs{ + BlobTx: tx, + Blobs: tx.Sidecar.Blobs, + Commitments: tx.Sidecar.Commitments, + Proofs: tx.Sidecar.Proofs, + } + return rlp.Encode(b, inner) +} + +func (tx *BlobTx) decode(input []byte) error { + // Here we need to support two formats: the network protocol encoding of the tx (with + // blobs) or the canonical encoding without blobs. + // + // The two encodings can be distinguished by checking whether the first element of the + // input list is itself a list. + + outerList, _, err := rlp.SplitList(input) + if err != nil { + return err + } + firstElemKind, _, _, err := rlp.Split(outerList) + if err != nil { + return err + } + + if firstElemKind != rlp.List { + return rlp.DecodeBytes(input, tx) + } + // It's a tx with blobs. + var inner blobTxWithBlobs + if err := rlp.DecodeBytes(input, &inner); err != nil { + return err + } + *tx = *inner.BlobTx + tx.Sidecar = &BlobTxSidecar{ + Blobs: inner.Blobs, + Commitments: inner.Commitments, + Proofs: inner.Proofs, + } + return nil +} + +func blobHash(commit *kzg4844.Commitment) common.Hash { + hasher := sha256.New() + hasher.Write(commit[:]) + var vhash common.Hash + hasher.Sum(vhash[:0]) + vhash[0] = params.BlobTxHashVersion + return vhash +} diff --git a/core/types/tx_blob_test.go b/core/types/tx_blob_test.go new file mode 100644 index 0000000000..44ac48cc6f --- /dev/null +++ b/core/types/tx_blob_test.go @@ -0,0 +1,90 @@ +package types + +import ( + "crypto/ecdsa" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/crypto/kzg4844" + "github.com/holiman/uint256" +) + +// This test verifies that tx.Hash() is not affected by presence of a BlobTxSidecar. +func TestBlobTxHashing(t *testing.T) { + key, _ := crypto.GenerateKey() + withBlobs := createEmptyBlobTx(key, true) + withBlobsStripped := withBlobs.WithoutBlobTxSidecar() + withoutBlobs := createEmptyBlobTx(key, false) + + hash := withBlobs.Hash() + t.Log("tx hash:", hash) + + if h := withBlobsStripped.Hash(); h != hash { + t.Fatal("wrong tx hash after WithoutBlobTxSidecar:", h) + } + if h := withoutBlobs.Hash(); h != hash { + t.Fatal("wrong tx hash on tx created without sidecar:", h) + } +} + +// This test verifies that tx.Size() takes BlobTxSidecar into account. +func TestBlobTxSize(t *testing.T) { + key, _ := crypto.GenerateKey() + withBlobs := createEmptyBlobTx(key, true) + withBlobsStripped := withBlobs.WithoutBlobTxSidecar() + withoutBlobs := createEmptyBlobTx(key, false) + + withBlobsEnc, _ := withBlobs.MarshalBinary() + withoutBlobsEnc, _ := withoutBlobs.MarshalBinary() + + size := withBlobs.Size() + t.Log("size with blobs:", size) + + sizeNoBlobs := withoutBlobs.Size() + t.Log("size without blobs:", sizeNoBlobs) + + if size != uint64(len(withBlobsEnc)) { + t.Error("wrong size with blobs:", size, "encoded length:", len(withBlobsEnc)) + } + if sizeNoBlobs != uint64(len(withoutBlobsEnc)) { + t.Error("wrong size without blobs:", sizeNoBlobs, "encoded length:", len(withoutBlobsEnc)) + } + if sizeNoBlobs >= size { + t.Error("size without blobs >= size with blobs") + } + if sz := withBlobsStripped.Size(); sz != sizeNoBlobs { + t.Fatal("wrong size on tx after WithoutBlobTxSidecar:", sz) + } +} + +var ( + emptyBlob = kzg4844.Blob{} + emptyBlobCommit, _ = kzg4844.BlobToCommitment(emptyBlob) + emptyBlobProof, _ = kzg4844.ComputeBlobProof(emptyBlob, emptyBlobCommit) +) + +func createEmptyBlobTx(key *ecdsa.PrivateKey, withSidecar bool) *Transaction { + sidecar := &BlobTxSidecar{ + Blobs: []kzg4844.Blob{emptyBlob}, + Commitments: []kzg4844.Commitment{emptyBlobCommit}, + Proofs: []kzg4844.Proof{emptyBlobProof}, + } + blobtx := &BlobTx{ + ChainID: uint256.NewInt(1), + Nonce: 5, + GasTipCap: uint256.NewInt(22), + GasFeeCap: uint256.NewInt(5), + Gas: 25000, + To: common.Address{0x03, 0x04, 0x05}, + Value: uint256.NewInt(99), + Data: make([]byte, 50), + BlobFeeCap: uint256.NewInt(15), + BlobHashes: sidecar.BlobHashes(), + } + if withSidecar { + blobtx.Sidecar = sidecar + } + signer := NewCancunSigner(blobtx.ChainID.ToBig()) + return MustSignNewTx(key, signer, blobtx) +} diff --git a/core/types/tx_dynamic_fee.go b/core/types/tx_dynamic_fee.go index 47b870abbf..8b5b514fde 100644 --- a/core/types/tx_dynamic_fee.go +++ b/core/types/tx_dynamic_fee.go @@ -17,9 +17,11 @@ package types import ( + "bytes" "math/big" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/rlp" ) // DynamicFeeTx represents an EIP-1559 transaction. @@ -83,20 +85,17 @@ func (tx *DynamicFeeTx) copy() TxData { } // accessors for innerTx. -func (tx *DynamicFeeTx) txType() byte { return DynamicFeeTxType } -func (tx *DynamicFeeTx) chainID() *big.Int { return tx.ChainID } -func (tx *DynamicFeeTx) accessList() AccessList { return tx.AccessList } -func (tx *DynamicFeeTx) data() []byte { return tx.Data } -func (tx *DynamicFeeTx) gas() uint64 { return tx.Gas } -func (tx *DynamicFeeTx) gasFeeCap() *big.Int { return tx.GasFeeCap } -func (tx *DynamicFeeTx) gasTipCap() *big.Int { return tx.GasTipCap } -func (tx *DynamicFeeTx) gasPrice() *big.Int { return tx.GasFeeCap } -func (tx *DynamicFeeTx) value() *big.Int { return tx.Value } -func (tx *DynamicFeeTx) nonce() uint64 { return tx.Nonce } -func (tx *DynamicFeeTx) to() *common.Address { return tx.To } -func (tx *DynamicFeeTx) blobGas() uint64 { return 0 } -func (tx *DynamicFeeTx) blobGasFeeCap() *big.Int { return nil } -func (tx *DynamicFeeTx) blobHashes() []common.Hash { return nil } +func (tx *DynamicFeeTx) txType() byte { return DynamicFeeTxType } +func (tx *DynamicFeeTx) chainID() *big.Int { return tx.ChainID } +func (tx *DynamicFeeTx) accessList() AccessList { return tx.AccessList } +func (tx *DynamicFeeTx) data() []byte { return tx.Data } +func (tx *DynamicFeeTx) gas() uint64 { return tx.Gas } +func (tx *DynamicFeeTx) gasFeeCap() *big.Int { return tx.GasFeeCap } +func (tx *DynamicFeeTx) gasTipCap() *big.Int { return tx.GasTipCap } +func (tx *DynamicFeeTx) gasPrice() *big.Int { return tx.GasFeeCap } +func (tx *DynamicFeeTx) value() *big.Int { return tx.Value } +func (tx *DynamicFeeTx) nonce() uint64 { return tx.Nonce } +func (tx *DynamicFeeTx) to() *common.Address { return tx.To } func (tx *DynamicFeeTx) effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int { if baseFee == nil { @@ -116,3 +115,11 @@ func (tx *DynamicFeeTx) rawSignatureValues() (v, r, s *big.Int) { func (tx *DynamicFeeTx) setSignatureValues(chainID, v, r, s *big.Int) { tx.ChainID, tx.V, tx.R, tx.S = chainID, v, r, s } + +func (tx *DynamicFeeTx) encode(b *bytes.Buffer) error { + return rlp.Encode(b, tx) +} + +func (tx *DynamicFeeTx) decode(input []byte) error { + return rlp.DecodeBytes(input, tx) +} diff --git a/core/types/tx_legacy.go b/core/types/tx_legacy.go index 902e70cf94..71025b78fc 100644 --- a/core/types/tx_legacy.go +++ b/core/types/tx_legacy.go @@ -17,6 +17,7 @@ package types import ( + "bytes" "math/big" "github.com/ethereum/go-ethereum/common" @@ -91,20 +92,17 @@ func (tx *LegacyTx) copy() TxData { } // accessors for innerTx. -func (tx *LegacyTx) txType() byte { return LegacyTxType } -func (tx *LegacyTx) chainID() *big.Int { return deriveChainId(tx.V) } -func (tx *LegacyTx) accessList() AccessList { return nil } -func (tx *LegacyTx) data() []byte { return tx.Data } -func (tx *LegacyTx) gas() uint64 { return tx.Gas } -func (tx *LegacyTx) gasPrice() *big.Int { return tx.GasPrice } -func (tx *LegacyTx) gasTipCap() *big.Int { return tx.GasPrice } -func (tx *LegacyTx) gasFeeCap() *big.Int { return tx.GasPrice } -func (tx *LegacyTx) value() *big.Int { return tx.Value } -func (tx *LegacyTx) nonce() uint64 { return tx.Nonce } -func (tx *LegacyTx) to() *common.Address { return tx.To } -func (tx *LegacyTx) blobGas() uint64 { return 0 } -func (tx *LegacyTx) blobGasFeeCap() *big.Int { return nil } -func (tx *LegacyTx) blobHashes() []common.Hash { return nil } +func (tx *LegacyTx) txType() byte { return LegacyTxType } +func (tx *LegacyTx) chainID() *big.Int { return deriveChainId(tx.V) } +func (tx *LegacyTx) accessList() AccessList { return nil } +func (tx *LegacyTx) data() []byte { return tx.Data } +func (tx *LegacyTx) gas() uint64 { return tx.Gas } +func (tx *LegacyTx) gasPrice() *big.Int { return tx.GasPrice } +func (tx *LegacyTx) gasTipCap() *big.Int { return tx.GasPrice } +func (tx *LegacyTx) gasFeeCap() *big.Int { return tx.GasPrice } +func (tx *LegacyTx) value() *big.Int { return tx.Value } +func (tx *LegacyTx) nonce() uint64 { return tx.Nonce } +func (tx *LegacyTx) to() *common.Address { return tx.To } func (tx *LegacyTx) effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int { return dst.Set(tx.GasPrice) @@ -117,3 +115,11 @@ func (tx *LegacyTx) rawSignatureValues() (v, r, s *big.Int) { func (tx *LegacyTx) setSignatureValues(chainID, v, r, s *big.Int) { tx.V, tx.R, tx.S = v, r, s } + +func (tx *LegacyTx) encode(*bytes.Buffer) error { + panic("encode called on LegacyTx") +} + +func (tx *LegacyTx) decode([]byte) error { + panic("decode called on LegacyTx)") +} diff --git a/core/vm/contracts.go b/core/vm/contracts.go index cb6f5de93c..2da5d93c39 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -20,6 +20,7 @@ import ( "crypto/sha256" "encoding/binary" "errors" + "fmt" "math/big" "github.com/ethereum/go-ethereum/common" @@ -28,6 +29,7 @@ import ( "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" "golang.org/x/crypto/ripemd160" ) @@ -93,6 +95,21 @@ var PrecompiledContractsBerlin = PrecompiledContracts{ common.BytesToAddress([]byte{9}): &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 = PrecompiledContracts{ @@ -108,6 +125,7 @@ var PrecompiledContractsBLS = PrecompiledContracts{ } var ( + PrecompiledAddressesCancun []common.Address PrecompiledAddressesBerlin []common.Address PrecompiledAddressesIstanbul []common.Address PrecompiledAddressesByzantium []common.Address @@ -127,6 +145,9 @@ func init() { for k := range PrecompiledContractsBerlin { PrecompiledAddressesBerlin = append(PrecompiledAddressesBerlin, k) } + for k := range PrecompiledContractsCancun { + PrecompiledAddressesCancun = append(PrecompiledAddressesCancun, k) + } } // Copy returns a copy of the precompiled contracts. @@ -155,6 +176,8 @@ func ActivePrecompiledContracts(rules params.Rules) PrecompiledContracts { // ActivePrecompiles returns the precompile addresses enabled with the current configuration. func ActivePrecompiles(rules params.Rules) []common.Address { switch { + case rules.IsCancun: + return PrecompiledAddressesCancun case rules.IsBerlin: return PrecompiledAddressesBerlin case rules.IsIstanbul: @@ -1074,3 +1097,67 @@ func (c *bls12381MapG2) Run(input []byte) ([]byte, error) { // Encode the G2 point to 256 bytes return g.EncodePoint(r), nil } + +// kzgPointEvaluation implements the EIP-4844 point evaluation precompile. +type kzgPointEvaluation struct{} + +// RequiredGas estimates the gas required for running the point evaluation precompile. +func (b *kzgPointEvaluation) RequiredGas(input []byte) uint64 { + return params.BlobTxPointEvaluationPrecompileGas +} + +const ( + blobVerifyInputLength = 192 // Max input length for the point evaluation precompile. + blobCommitmentVersionKZG uint8 = 0x01 // Version byte for the point evaluation precompile. + blobPrecompileReturnValue = "000000000000000000000000000000000000000000000000000000000000100073eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001" +) + +var ( + errBlobVerifyInvalidInputLength = errors.New("invalid input length") + errBlobVerifyMismatchedVersion = errors.New("mismatched versioned hash") + errBlobVerifyKZGProof = errors.New("error verifying kzg proof") +) + +// Run executes the point evaluation precompile. +func (b *kzgPointEvaluation) Run(input []byte) ([]byte, error) { + if len(input) != blobVerifyInputLength { + return nil, errBlobVerifyInvalidInputLength + } + // versioned hash: first 32 bytes + var versionedHash common.Hash + copy(versionedHash[:], input[:]) + + var ( + point kzg4844.Point + claim kzg4844.Claim + ) + // Evaluation point: next 32 bytes + copy(point[:], input[32:]) + // Expected output: next 32 bytes + copy(claim[:], input[64:]) + + // input kzg point: next 48 bytes + var commitment kzg4844.Commitment + copy(commitment[:], input[96:]) + if kZGToVersionedHash(commitment) != versionedHash { + return nil, errBlobVerifyMismatchedVersion + } + + // Proof: next 48 bytes + var proof kzg4844.Proof + copy(proof[:], input[144:]) + + if err := kzg4844.VerifyProof(commitment, point, claim, proof); err != nil { + return nil, fmt.Errorf("%w: %v", errBlobVerifyKZGProof, err) + } + + return common.Hex2Bytes(blobPrecompileReturnValue), nil +} + +// kZGToVersionedHash implements kzg_to_versioned_hash from EIP-4844 +func kZGToVersionedHash(kzg kzg4844.Commitment) common.Hash { + h := sha256.Sum256(kzg[:]) + h[0] = blobCommitmentVersionKZG + + return h +} diff --git a/core/vm/contracts_test.go b/core/vm/contracts_test.go index b22d999e6c..f40e2c8f9e 100644 --- a/core/vm/contracts_test.go +++ b/core/vm/contracts_test.go @@ -56,15 +56,17 @@ var allPrecompiles = map[common.Address]PrecompiledContract{ common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{}, common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{}, common.BytesToAddress([]byte{9}): &blake2F{}, - 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{0x0a}): &kzgPointEvaluation{}, + + common.BytesToAddress([]byte{0x0f, 0x0a}): &bls12381G1Add{}, + common.BytesToAddress([]byte{0x0f, 0x0b}): &bls12381G1Mul{}, + common.BytesToAddress([]byte{0x0f, 0x0c}): &bls12381G1MultiExp{}, + common.BytesToAddress([]byte{0x0f, 0x0d}): &bls12381G2Add{}, + common.BytesToAddress([]byte{0x0f, 0x0e}): &bls12381G2Mul{}, + common.BytesToAddress([]byte{0x0f, 0x0f}): &bls12381G2MultiExp{}, + common.BytesToAddress([]byte{0x0f, 0x10}): &bls12381Pairing{}, + common.BytesToAddress([]byte{0x0f, 0x11}): &bls12381MapG1{}, + common.BytesToAddress([]byte{0x0f, 0x12}): &bls12381MapG2{}, } // EIP-152 test vectors @@ -302,36 +304,38 @@ func benchJson(name, addr string, b *testing.B) { } } -func TestPrecompiledBLS12381G1Add(t *testing.T) { testJson("blsG1Add", "0a", t) } -func TestPrecompiledBLS12381G1Mul(t *testing.T) { testJson("blsG1Mul", "0b", t) } -func TestPrecompiledBLS12381G1MultiExp(t *testing.T) { testJson("blsG1MultiExp", "0c", t) } -func TestPrecompiledBLS12381G2Add(t *testing.T) { testJson("blsG2Add", "0d", t) } -func TestPrecompiledBLS12381G2Mul(t *testing.T) { testJson("blsG2Mul", "0e", t) } -func TestPrecompiledBLS12381G2MultiExp(t *testing.T) { testJson("blsG2MultiExp", "0f", t) } -func TestPrecompiledBLS12381Pairing(t *testing.T) { testJson("blsPairing", "10", t) } -func TestPrecompiledBLS12381MapG1(t *testing.T) { testJson("blsMapG1", "11", t) } -func TestPrecompiledBLS12381MapG2(t *testing.T) { testJson("blsMapG2", "12", t) } +func TestPrecompiledBLS12381G1Add(t *testing.T) { testJson("blsG1Add", "f0a", t) } +func TestPrecompiledBLS12381G1Mul(t *testing.T) { testJson("blsG1Mul", "f0b", t) } +func TestPrecompiledBLS12381G1MultiExp(t *testing.T) { testJson("blsG1MultiExp", "f0c", t) } +func TestPrecompiledBLS12381G2Add(t *testing.T) { testJson("blsG2Add", "f0d", t) } +func TestPrecompiledBLS12381G2Mul(t *testing.T) { testJson("blsG2Mul", "f0e", t) } +func TestPrecompiledBLS12381G2MultiExp(t *testing.T) { testJson("blsG2MultiExp", "f0f", t) } +func TestPrecompiledBLS12381Pairing(t *testing.T) { testJson("blsPairing", "f10", t) } +func TestPrecompiledBLS12381MapG1(t *testing.T) { testJson("blsMapG1", "f11", t) } +func TestPrecompiledBLS12381MapG2(t *testing.T) { testJson("blsMapG2", "f12", t) } -func BenchmarkPrecompiledBLS12381G1Add(b *testing.B) { benchJson("blsG1Add", "0a", b) } -func BenchmarkPrecompiledBLS12381G1Mul(b *testing.B) { benchJson("blsG1Mul", "0b", b) } -func BenchmarkPrecompiledBLS12381G1MultiExp(b *testing.B) { benchJson("blsG1MultiExp", "0c", b) } -func BenchmarkPrecompiledBLS12381G2Add(b *testing.B) { benchJson("blsG2Add", "0d", b) } -func BenchmarkPrecompiledBLS12381G2Mul(b *testing.B) { benchJson("blsG2Mul", "0e", b) } -func BenchmarkPrecompiledBLS12381G2MultiExp(b *testing.B) { benchJson("blsG2MultiExp", "0f", b) } -func BenchmarkPrecompiledBLS12381Pairing(b *testing.B) { benchJson("blsPairing", "10", b) } -func BenchmarkPrecompiledBLS12381MapG1(b *testing.B) { benchJson("blsMapG1", "11", b) } -func BenchmarkPrecompiledBLS12381MapG2(b *testing.B) { benchJson("blsMapG2", "12", b) } +func TestPrecompiledPointEvaluation(t *testing.T) { testJson("pointEvaluation", "0a", t) } + +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) } +func BenchmarkPrecompiledBLS12381G2Add(b *testing.B) { benchJson("blsG2Add", "f0d", b) } +func BenchmarkPrecompiledBLS12381G2Mul(b *testing.B) { benchJson("blsG2Mul", "f0e", b) } +func BenchmarkPrecompiledBLS12381G2MultiExp(b *testing.B) { benchJson("blsG2MultiExp", "f0f", b) } +func BenchmarkPrecompiledBLS12381Pairing(b *testing.B) { benchJson("blsPairing", "f10", b) } +func BenchmarkPrecompiledBLS12381MapG1(b *testing.B) { benchJson("blsMapG1", "f11", b) } +func BenchmarkPrecompiledBLS12381MapG2(b *testing.B) { benchJson("blsMapG2", "f12", b) } // Failure tests -func TestPrecompiledBLS12381G1AddFail(t *testing.T) { testJsonFail("blsG1Add", "0a", t) } -func TestPrecompiledBLS12381G1MulFail(t *testing.T) { testJsonFail("blsG1Mul", "0b", t) } -func TestPrecompiledBLS12381G1MultiExpFail(t *testing.T) { testJsonFail("blsG1MultiExp", "0c", t) } -func TestPrecompiledBLS12381G2AddFail(t *testing.T) { testJsonFail("blsG2Add", "0d", t) } -func TestPrecompiledBLS12381G2MulFail(t *testing.T) { testJsonFail("blsG2Mul", "0e", t) } -func TestPrecompiledBLS12381G2MultiExpFail(t *testing.T) { testJsonFail("blsG2MultiExp", "0f", t) } -func TestPrecompiledBLS12381PairingFail(t *testing.T) { testJsonFail("blsPairing", "10", t) } -func TestPrecompiledBLS12381MapG1Fail(t *testing.T) { testJsonFail("blsMapG1", "11", t) } -func TestPrecompiledBLS12381MapG2Fail(t *testing.T) { testJsonFail("blsMapG2", "12", t) } +func TestPrecompiledBLS12381G1AddFail(t *testing.T) { testJsonFail("blsG1Add", "f0a", t) } +func TestPrecompiledBLS12381G1MulFail(t *testing.T) { testJsonFail("blsG1Mul", "f0b", t) } +func TestPrecompiledBLS12381G1MultiExpFail(t *testing.T) { testJsonFail("blsG1MultiExp", "f0c", t) } +func TestPrecompiledBLS12381G2AddFail(t *testing.T) { testJsonFail("blsG2Add", "f0d", t) } +func TestPrecompiledBLS12381G2MulFail(t *testing.T) { testJsonFail("blsG2Mul", "f0e", t) } +func TestPrecompiledBLS12381G2MultiExpFail(t *testing.T) { testJsonFail("blsG2MultiExp", "f0f", t) } +func TestPrecompiledBLS12381PairingFail(t *testing.T) { testJsonFail("blsPairing", "f10", t) } +func TestPrecompiledBLS12381MapG1Fail(t *testing.T) { testJsonFail("blsMapG1", "f11", t) } +func TestPrecompiledBLS12381MapG2Fail(t *testing.T) { testJsonFail("blsMapG2", "f12", t) } func loadJson(name string) ([]precompiledTest, error) { data, err := os.ReadFile(fmt.Sprintf("testdata/precompiles/%v.json", name)) diff --git a/core/vm/eips.go b/core/vm/eips.go index 29ff27c552..704c1ce127 100644 --- a/core/vm/eips.go +++ b/core/vm/eips.go @@ -26,6 +26,8 @@ import ( ) var activators = map[int]func(*JumpTable){ + 5656: enable5656, + 6780: enable6780, 3855: enable3855, 3860: enable3860, 3529: enable3529, @@ -235,9 +237,69 @@ func opPush0(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by return nil, nil } -// ebnable3860 enables "EIP-3860: Limit and meter initcode" +// enable3860 enables "EIP-3860: Limit and meter initcode" // https://eips.ethereum.org/EIPS/eip-3860 func enable3860(jt *JumpTable) { jt[CREATE].dynamicGas = gasCreateEip3860 jt[CREATE2].dynamicGas = gasCreate2Eip3860 } + +// enable5656 enables EIP-5656 (MCOPY opcode) +// https://eips.ethereum.org/EIPS/eip-5656 +func enable5656(jt *JumpTable) { + jt[MCOPY] = &operation{ + execute: opMcopy, + constantGas: GasFastestStep, + dynamicGas: gasMcopy, + minStack: minStack(3, 0), + maxStack: maxStack(3, 0), + memorySize: memoryMcopy, + } +} + +// opMcopy implements the MCOPY opcode (https://eips.ethereum.org/EIPS/eip-5656) +func opMcopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + var ( + dst = scope.Stack.pop() + src = scope.Stack.pop() + length = scope.Stack.pop() + ) + // These values are checked for overflow during memory expansion calculation + // (the memorySize function on the opcode). + scope.Memory.Copy(dst.Uint64(), src.Uint64(), length.Uint64()) + return nil, nil +} + +// opBlobHash implements the BLOBHASH opcode +func opBlobHash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + index := scope.Stack.peek() + if index.LtUint64(uint64(len(interpreter.evm.TxContext.BlobHashes))) { + blobHash := interpreter.evm.TxContext.BlobHashes[index.Uint64()] + index.SetBytes32(blobHash[:]) + } else { + index.Clear() + } + return nil, nil +} + +// enable4844 applies EIP-4844 (DATAHASH opcode) +func enable4844(jt *JumpTable) { + // New opcode + jt[BLOBHASH] = &operation{ + execute: opBlobHash, + constantGas: GasFastestStep, + minStack: minStack(1, 1), + maxStack: maxStack(1, 1), + } +} + +// enable6780 applies EIP-6780 (deactivate SELFDESTRUCT) +func enable6780(jt *JumpTable) { + jt[SELFDESTRUCT] = &operation{ + execute: opSelfdestruct6780, + dynamicGas: gasSelfdestructEIP3529, + constantGas: params.SelfdestructGasEIP150, + minStack: minStack(1, 0), + maxStack: maxStack(1, 0), + } +} diff --git a/core/vm/evm.go b/core/vm/evm.go index a72822fcec..b38c9e6c69 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -21,15 +21,12 @@ import ( "sync/atomic" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" ) -// emptyCodeHash is used by create to ensure deployment is disallowed to already -// deployed contract addresses (relevant after the account abstraction). -var emptyCodeHash = crypto.Keccak256Hash(nil) - type ( // CanTransferFunc is the signature of a transfer guard function CanTransferFunc func(StateDB, common.Address, *big.Int) bool @@ -57,21 +54,23 @@ type BlockContext struct { GetHash GetHashFunc // Block information - Coinbase common.Address // Provides information for COINBASE - GasLimit uint64 // Provides information for GASLIMIT - BlockNumber *big.Int // Provides information for NUMBER - Time uint64 // Provides information for TIME - Difficulty *big.Int // Provides information for DIFFICULTY - BaseFee *big.Int // Provides information for BASEFEE - Random *common.Hash // Provides information for PREVRANDAO + Coinbase common.Address // Provides information for COINBASE + GasLimit uint64 // Provides information for GASLIMIT + BlockNumber *big.Int // Provides information for NUMBER + Time uint64 // Provides information for TIME + Difficulty *big.Int // Provides information for DIFFICULTY + BaseFee *big.Int // Provides information for BASEFEE + Random *common.Hash // Provides information for PREVRANDAO + ExcessBlobGas *uint64 // ExcessBlobGas field in the header, needed to compute the data } // TxContext provides the EVM with information about a transaction. // 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 + Origin common.Address // Provides information for ORIGIN + GasPrice *big.Int // Provides information for GASPRICE + BlobHashes []common.Hash // Provides information for BLOBHASH } // EVM is the Ethereum Virtual Machine base object and provides @@ -434,7 +433,7 @@ 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 != emptyCodeHash) { + if evm.StateDB.GetNonce(address) != 0 || (contractHash != (common.Hash{}) && contractHash != types.EmptyCodeHash) { return nil, common.Address{}, 0, ErrContractAddressCollision } // Create a new account on the state diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go index 4f961ef4db..5153c8b7a3 100644 --- a/core/vm/gas_table.go +++ b/core/vm/gas_table.go @@ -60,6 +60,7 @@ func memoryGasCost(mem *Memory, newMemSize uint64) (uint64, error) { // as argument: // CALLDATACOPY (stack position 2) // CODECOPY (stack position 2) +// MCOPY (stack position 2) // EXTCODECOPY (stack position 3) // RETURNDATACOPY (stack position 2) func memoryCopierGas(stackpos int) gasFunc { @@ -89,6 +90,7 @@ func memoryCopierGas(stackpos int) gasFunc { var ( gasCallDataCopy = memoryCopierGas(2) gasCodeCopy = memoryCopierGas(2) + gasMcopy = memoryCopierGas(2) gasExtCodeCopy = memoryCopierGas(3) gasReturnDataCopy = memoryCopierGas(2) ) @@ -470,7 +472,7 @@ func gasSelfdestruct(evm *EVM, contract *Contract, stack *Stack, mem *Memory, me } } - if !evm.StateDB.HasSuicided(contract.Address()) { + if !evm.StateDB.HasSelfDestructed(contract.Address()) { evm.StateDB.AddRefund(params.SelfdestructRefundGas) } return gas, nil diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 505aef4127..2105201fce 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -408,7 +408,7 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) // emptyCodeHash. If the precompile account is not transferred any amount on a private or // customized chain, the return value will be zero. // -// 5. Caller tries to get the code hash for an account which is marked as suicided +// 5. Caller tries to get the code hash for an account which is marked as self-destructed // in the current transaction, the code hash of this account should be returned. // // 6. Caller tries to get the code hash for an account which is marked as deleted, this @@ -821,7 +821,23 @@ 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.Suicide(scope.Contract.Address()) + 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) + tracer.CaptureExit([]byte{}, 0, nil) + } + return nil, errStopToken +} + +func opSelfdestruct6780(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + if interpreter.readOnly { + return nil, ErrWriteProtection + } + 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.Selfdestruct6780(scope.Contract.Address()) if tracer := interpreter.evm.Config.Tracer; tracer != nil { tracer.CaptureEnter(SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance) tracer.CaptureExit([]byte{}, 0, nil) diff --git a/core/vm/instructions_test.go b/core/vm/instructions_test.go index 2a66f8163e..807073336d 100644 --- a/core/vm/instructions_test.go +++ b/core/vm/instructions_test.go @@ -22,9 +22,11 @@ import ( "fmt" "math/big" "os" + "strings" "testing" "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" @@ -723,7 +725,7 @@ func TestRandom(t *testing.T) { for _, tt := range []testcase{ {name: "empty hash", random: common.Hash{}}, {name: "1", random: common.Hash{0}}, - {name: "emptyCodeHash", random: emptyCodeHash}, + {name: "emptyCodeHash", random: types.EmptyCodeHash}, {name: "hash(0x010203)", random: crypto.Keccak256Hash([]byte{0x01, 0x02, 0x03})}, } { var ( @@ -746,3 +748,183 @@ func TestRandom(t *testing.T) { } } } + +func TestBlobHash(t *testing.T) { + type testcase struct { + name string + idx uint64 + expect common.Hash + hashes []common.Hash + } + var ( + zero = common.Hash{0} + one = common.Hash{1} + two = common.Hash{2} + three = common.Hash{3} + ) + for _, tt := range []testcase{ + {name: "[{1}]", idx: 0, expect: one, hashes: []common.Hash{one}}, + {name: "[1,{2},3]", idx: 2, expect: three, hashes: []common.Hash{one, two, three}}, + {name: "out-of-bounds (empty)", idx: 10, expect: zero, hashes: []common.Hash{}}, + {name: "out-of-bounds", idx: 25, expect: zero, hashes: []common.Hash{one, two, three}}, + {name: "out-of-bounds (nil)", idx: 25, expect: zero, hashes: nil}, + } { + var ( + env = NewEVM(BlockContext{}, TxContext{BlobHashes: tt.hashes}, nil, params.TestChainConfig, Config{}) + stack = newstack() + pc = uint64(0) + evmInterpreter = env.interpreter + ) + stack.push(uint256.NewInt(tt.idx)) + opBlobHash(&pc, evmInterpreter, &ScopeContext{nil, stack, nil}) + if len(stack.data) != 1 { + t.Errorf("Expected one item on stack after %v, got %d: ", tt.name, len(stack.data)) + } + actual := stack.pop() + expected, overflow := uint256.FromBig(new(big.Int).SetBytes(tt.expect.Bytes())) + if overflow { + t.Errorf("Testcase %v: invalid overflow", tt.name) + } + if actual.Cmp(expected) != 0 { + t.Errorf("Testcase %v: expected %x, got %x", tt.name, expected, actual) + } + } +} + +func TestOpMCopy(t *testing.T) { + // Test cases from https://eips.ethereum.org/EIPS/eip-5656#test-cases + for i, tc := range []struct { + dst, src, len string + pre string + want string + wantGas uint64 + }{ + { // MCOPY 0 32 32 - copy 32 bytes from offset 32 to offset 0. + dst: "0x0", src: "0x20", len: "0x20", + pre: "0000000000000000000000000000000000000000000000000000000000000000 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + want: "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + wantGas: 6, + }, + + { // MCOPY 0 0 32 - copy 32 bytes from offset 0 to offset 0. + dst: "0x0", src: "0x0", len: "0x20", + pre: "0101010101010101010101010101010101010101010101010101010101010101", + want: "0101010101010101010101010101010101010101010101010101010101010101", + wantGas: 6, + }, + { // MCOPY 0 1 8 - copy 8 bytes from offset 1 to offset 0 (overlapping). + dst: "0x0", src: "0x1", len: "0x8", + pre: "000102030405060708 000000000000000000000000000000000000000000000000", + want: "010203040506070808 000000000000000000000000000000000000000000000000", + wantGas: 6, + }, + { // MCOPY 1 0 8 - copy 8 bytes from offset 0 to offset 1 (overlapping). + dst: "0x1", src: "0x0", len: "0x8", + pre: "000102030405060708 000000000000000000000000000000000000000000000000", + want: "000001020304050607 000000000000000000000000000000000000000000000000", + wantGas: 6, + }, + // Tests below are not in the EIP, but maybe should be added + { // MCOPY 0xFFFFFFFFFFFF 0xFFFFFFFFFFFF 0 - copy zero bytes from out-of-bounds index(overlapping). + dst: "0xFFFFFFFFFFFF", src: "0xFFFFFFFFFFFF", len: "0x0", + pre: "11", + want: "11", + wantGas: 3, + }, + { // MCOPY 0xFFFFFFFFFFFF 0 0 - copy zero bytes from start of mem to out-of-bounds. + dst: "0xFFFFFFFFFFFF", src: "0x0", len: "0x0", + pre: "11", + want: "11", + wantGas: 3, + }, + { // MCOPY 0 0xFFFFFFFFFFFF 0 - copy zero bytes from out-of-bounds to start of mem + dst: "0x0", src: "0xFFFFFFFFFFFF", len: "0x0", + pre: "11", + want: "11", + wantGas: 3, + }, + { // MCOPY - copy 1 from space outside of uint64 space + dst: "0x0", src: "0x10000000000000000", len: "0x1", + pre: "0", + }, + { // MCOPY - copy 1 from 0 to space outside of uint64 + dst: "0x10000000000000000", src: "0x0", len: "0x1", + pre: "0", + }, + { // MCOPY - copy nothing from 0 to space outside of uint64 + dst: "0x10000000000000000", src: "0x0", len: "0x0", + pre: "", + want: "", + wantGas: 3, + }, + { // MCOPY - copy 1 from 0x20 to 0x10, with no prior allocated mem + dst: "0x10", src: "0x20", len: "0x1", + pre: "", + // 64 bytes + want: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + wantGas: 12, + }, + { // MCOPY - copy 1 from 0x19 to 0x10, with no prior allocated mem + dst: "0x10", src: "0x19", len: "0x1", + pre: "", + // 32 bytes + want: "0x0000000000000000000000000000000000000000000000000000000000000000", + wantGas: 9, + }, + } { + var ( + env = NewEVM(BlockContext{}, TxContext{}, nil, params.TestChainConfig, Config{}) + stack = newstack() + pc = uint64(0) + evmInterpreter = env.interpreter + ) + data := common.FromHex(strings.ReplaceAll(tc.pre, " ", "")) + // Set pre + mem := NewMemory() + mem.Resize(uint64(len(data))) + mem.Set(0, uint64(len(data)), data) + // Push stack args + len, _ := uint256.FromHex(tc.len) + src, _ := uint256.FromHex(tc.src) + dst, _ := uint256.FromHex(tc.dst) + + stack.push(len) + stack.push(src) + stack.push(dst) + wantErr := (tc.wantGas == 0) + // Calc mem expansion + var memorySize uint64 + if memSize, overflow := memoryMcopy(stack); overflow { + if wantErr { + continue + } + t.Errorf("overflow") + } else { + var overflow bool + if memorySize, overflow = math.SafeMul(toWordSize(memSize), 32); overflow { + t.Error(ErrGasUintOverflow) + } + } + // and the dynamic cost + var haveGas uint64 + if dynamicCost, err := gasMcopy(env, nil, stack, mem, memorySize); err != nil { + t.Error(err) + } else { + haveGas = GasFastestStep + dynamicCost + } + // Expand mem + if memorySize > 0 { + mem.Resize(memorySize) + } + // Do the copy + opMcopy(&pc, evmInterpreter, &ScopeContext{mem, stack, nil}) + want := common.FromHex(strings.ReplaceAll(tc.want, " ", "")) + if have := mem.store; !bytes.Equal(want, have) { + t.Errorf("case %d: \nwant: %#x\nhave: %#x\n", i, want, have) + } + wantGas := tc.wantGas + if haveGas != wantGas { + t.Errorf("case %d: gas wrong, want %d have %d\n", i, wantGas, haveGas) + } + } +} diff --git a/core/vm/interface.go b/core/vm/interface.go index b83f78307e..26814d3d2f 100644 --- a/core/vm/interface.go +++ b/core/vm/interface.go @@ -51,11 +51,13 @@ type StateDB interface { GetTransientState(addr common.Address, key common.Hash) common.Hash SetTransientState(addr common.Address, key, value common.Hash) - Suicide(common.Address) bool - HasSuicided(common.Address) bool + SelfDestruct(common.Address) + HasSelfDestructed(common.Address) bool + + Selfdestruct6780(common.Address) // Exist reports whether the given account exists in state. - // Notably this should also return true for suicided accounts. + // Notably this should also return true for self-destructed accounts. Exist(common.Address) bool // Empty returns whether the given account is empty. Empty // is defined according to EIP161 (balance = nonce = code = 0). diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 5b2082bc9e..873337850e 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -56,6 +56,8 @@ func NewEVMInterpreter(evm *EVM) *EVMInterpreter { // If jump table was not initialised we set the default one. var table *JumpTable switch { + case evm.chainRules.IsCancun: + table = &cancunInstructionSet case evm.chainRules.IsShanghai: table = &shanghaiInstructionSet case evm.chainRules.IsMerge: diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index a45287de80..702b186615 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -56,6 +56,7 @@ var ( londonInstructionSet = newLondonInstructionSet() mergeInstructionSet = newMergeInstructionSet() shanghaiInstructionSet = newShanghaiInstructionSet() + cancunInstructionSet = newCancunInstructionSet() ) // JumpTable contains the EVM opcodes supported at a given fork. @@ -79,10 +80,20 @@ func validate(jt JumpTable) JumpTable { return jt } +func newCancunInstructionSet() JumpTable { + instructionSet := newShanghaiInstructionSet() + enable4844(&instructionSet) // EIP-4844 (DATAHASH opcode) + enable1153(&instructionSet) // EIP-1153 "Transient Storage" + enable5656(&instructionSet) // EIP-5656 (MCOPY opcode) + enable6780(&instructionSet) // EIP-6780 SELFDESTRUCT only in same transaction + return validate(instructionSet) +} + func newShanghaiInstructionSet() JumpTable { instructionSet := newMergeInstructionSet() enable3855(&instructionSet) // PUSH0 instruction enable3860(&instructionSet) // Limit and meter initcode + return validate(instructionSet) } diff --git a/core/vm/jump_table_export.go b/core/vm/jump_table_export.go index 0d61b00ede..6ea47d63a2 100644 --- a/core/vm/jump_table_export.go +++ b/core/vm/jump_table_export.go @@ -26,10 +26,12 @@ import ( // the rules. func LookupInstructionSet(rules params.Rules) (JumpTable, error) { switch { + case rules.IsVerkle: + return newCancunInstructionSet(), errors.New("verkle-fork not defined yet") case rules.IsPrague: - return newShanghaiInstructionSet(), errors.New("prague-fork not defined yet") + return newCancunInstructionSet(), errors.New("prague-fork not defined yet") case rules.IsCancun: - return newShanghaiInstructionSet(), errors.New("cancun-fork not defined yet") + return newCancunInstructionSet(), nil case rules.IsShanghai: return newShanghaiInstructionSet(), nil case rules.IsMerge: diff --git a/core/vm/memory.go b/core/vm/memory.go index 35b7299960..e0202fd7c0 100644 --- a/core/vm/memory.go +++ b/core/vm/memory.go @@ -103,3 +103,14 @@ func (m *Memory) Len() int { func (m *Memory) Data() []byte { return m.store } + +// Copy copies data from the src position slice into the dst position. +// The source and destination may overlap. +// OBS: This operation assumes that any necessary memory expansion has already been performed, +// and this method may panic otherwise. +func (m *Memory) Copy(dst, src, len uint64) { + if len == 0 { + return + } + copy(m.store[dst:], m.store[src:src+len]) +} diff --git a/core/vm/memory_table.go b/core/vm/memory_table.go index e35ca84e0e..61a910a03d 100644 --- a/core/vm/memory_table.go +++ b/core/vm/memory_table.go @@ -48,6 +48,14 @@ func memoryMStore(stack *Stack) (uint64, bool) { return calcMemSize64WithUint(stack.Back(0), 32) } +func memoryMcopy(stack *Stack) (uint64, bool) { + mStart := stack.Back(0) // stack[0]: dest + if stack.Back(1).Gt(mStart) { + mStart = stack.Back(1) // stack[1]: source + } + return calcMemSize64(mStart, stack.Back(2)) // stack[2]: length +} + func memoryCreate(stack *Stack) (uint64, bool) { return calcMemSize64(stack.Back(1), stack.Back(2)) } diff --git a/core/vm/memory_test.go b/core/vm/memory_test.go new file mode 100644 index 0000000000..ba36f8023c --- /dev/null +++ b/core/vm/memory_test.go @@ -0,0 +1,69 @@ +package vm + +import ( + "bytes" + "strings" + "testing" + + "github.com/ethereum/go-ethereum/common" +) + +func TestMemoryCopy(t *testing.T) { + // Test cases from https://eips.ethereum.org/EIPS/eip-5656#test-cases + for i, tc := range []struct { + dst, src, len uint64 + pre string + want string + }{ + { // MCOPY 0 32 32 - copy 32 bytes from offset 32 to offset 0. + 0, 32, 32, + "0000000000000000000000000000000000000000000000000000000000000000 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + }, + + { // MCOPY 0 0 32 - copy 32 bytes from offset 0 to offset 0. + 0, 0, 32, + "0101010101010101010101010101010101010101010101010101010101010101", + "0101010101010101010101010101010101010101010101010101010101010101", + }, + { // MCOPY 0 1 8 - copy 8 bytes from offset 1 to offset 0 (overlapping). + 0, 1, 8, + "000102030405060708 000000000000000000000000000000000000000000000000", + "010203040506070808 000000000000000000000000000000000000000000000000", + }, + { // MCOPY 1 0 8 - copy 8 bytes from offset 0 to offset 1 (overlapping). + 1, 0, 8, + "000102030405060708 000000000000000000000000000000000000000000000000", + "000001020304050607 000000000000000000000000000000000000000000000000", + }, + // Tests below are not in the EIP, but maybe should be added + { // MCOPY 0xFFFFFFFFFFFF 0xFFFFFFFFFFFF 0 - copy zero bytes from out-of-bounds index(overlapping). + 0xFFFFFFFFFFFF, 0xFFFFFFFFFFFF, 0, + "11", + "11", + }, + { // MCOPY 0xFFFFFFFFFFFF 0 0 - copy zero bytes from start of mem to out-of-bounds. + 0xFFFFFFFFFFFF, 0, 0, + "11", + "11", + }, + { // MCOPY 0 0xFFFFFFFFFFFF 0 - copy zero bytes from out-of-bounds to start of mem + 0, 0xFFFFFFFFFFFF, 0, + "11", + "11", + }, + } { + m := NewMemory() + // Clean spaces + data := common.FromHex(strings.ReplaceAll(tc.pre, " ", "")) + // Set pre + m.Resize(uint64(len(data))) + m.Set(0, uint64(len(data)), data) + // Do the copy + m.Copy(tc.dst, tc.src, tc.len) + want := common.FromHex(strings.ReplaceAll(tc.want, " ", "")) + if have := m.store; !bytes.Equal(want, have) { + t.Errorf("case %d: want: %#x\nhave: %#x\n", i, want, have) + } + } +} diff --git a/core/vm/opcodes.go b/core/vm/opcodes.go index 910491c600..2929b8ce92 100644 --- a/core/vm/opcodes.go +++ b/core/vm/opcodes.go @@ -100,6 +100,7 @@ const ( CHAINID OpCode = 0x46 SELFBALANCE OpCode = 0x47 BASEFEE OpCode = 0x48 + BLOBHASH OpCode = 0x49 ) // 0x50 range - 'storage' and execution. @@ -116,6 +117,9 @@ const ( MSIZE OpCode = 0x59 GAS OpCode = 0x5a JUMPDEST OpCode = 0x5b + TLOAD OpCode = 0x5c + TSTORE OpCode = 0x5d + MCOPY OpCode = 0x5e PUSH0 OpCode = 0x5f ) @@ -204,12 +208,6 @@ const ( LOG4 ) -// 0xb0 range. -const ( - TLOAD OpCode = 0xb3 - TSTORE OpCode = 0xb4 -) - // 0xf0 range - closures. const ( CREATE OpCode = 0xf0 @@ -288,6 +286,7 @@ var opCodeToString = map[OpCode]string{ CHAINID: "CHAINID", SELFBALANCE: "SELFBALANCE", BASEFEE: "BASEFEE", + BLOBHASH: "BLOBHASH", // 0x50 range - 'storage' and execution. POP: "POP", @@ -302,6 +301,9 @@ var opCodeToString = map[OpCode]string{ MSIZE: "MSIZE", GAS: "GAS", JUMPDEST: "JUMPDEST", + TLOAD: "TLOAD", + TSTORE: "TSTORE", + MCOPY: "MCOPY", PUSH0: "PUSH0", // 0x60 range - pushes. @@ -381,10 +383,6 @@ var opCodeToString = map[OpCode]string{ LOG3: "LOG3", LOG4: "LOG4", - // 0xb0 range. - TLOAD: "TLOAD", - TSTORE: "TSTORE", - // 0xf0 range - closures. CREATE: "CREATE", CALL: "CALL", @@ -445,6 +443,7 @@ var stringToOp = map[string]OpCode{ "CALLDATACOPY": CALLDATACOPY, "CHAINID": CHAINID, "BASEFEE": BASEFEE, + "BLOBHASH": BLOBHASH, "DELEGATECALL": DELEGATECALL, "STATICCALL": STATICCALL, "CODESIZE": CODESIZE, @@ -474,6 +473,9 @@ var stringToOp = map[string]OpCode{ "MSIZE": MSIZE, "GAS": GAS, "JUMPDEST": JUMPDEST, + "TLOAD": TLOAD, + "TSTORE": TSTORE, + "MCOPY": MCOPY, "PUSH0": PUSH0, "PUSH1": PUSH1, "PUSH2": PUSH2, @@ -544,8 +546,6 @@ var stringToOp = map[string]OpCode{ "LOG2": LOG2, "LOG3": LOG3, "LOG4": LOG4, - "TLOAD": TLOAD, - "TSTORE": TSTORE, "CREATE": CREATE, "CREATE2": CREATE2, "CALL": CALL, diff --git a/core/vm/operations_acl.go b/core/vm/operations_acl.go index 551e1f5f11..04c6409ebd 100644 --- a/core/vm/operations_acl.go +++ b/core/vm/operations_acl.go @@ -235,7 +235,7 @@ func makeSelfdestructGasFn(refundsEnabled bool) gasFunc { if evm.StateDB.Empty(address) && evm.StateDB.GetBalance(contract.Address()).Sign() != 0 { gas += params.CreateBySelfdestructGas } - if refundsEnabled && !evm.StateDB.HasSuicided(contract.Address()) { + if refundsEnabled && !evm.StateDB.HasSelfDestructed(contract.Address()) { evm.StateDB.AddRefund(params.SelfdestructRefundGas) } return gas, nil diff --git a/core/vm/runtime/env.go b/core/vm/runtime/env.go index dcb0974284..7e330e0732 100644 --- a/core/vm/runtime/env.go +++ b/core/vm/runtime/env.go @@ -23,8 +23,9 @@ import ( func NewEnv(cfg *Config) *vm.EVM { txContext := vm.TxContext{ - Origin: cfg.Origin, - GasPrice: cfg.GasPrice, + Origin: cfg.Origin, + GasPrice: cfg.GasPrice, + BlobHashes: cfg.BlobHashes, } blockContext := vm.BlockContext{ CanTransfer: core.CanTransfer, @@ -36,6 +37,7 @@ func NewEnv(cfg *Config) *vm.EVM { Difficulty: cfg.Difficulty, GasLimit: cfg.GasLimit, BaseFee: cfg.BaseFee, + Random: cfg.Random, } return vm.NewEVM(blockContext, txContext, cfg.State, cfg.ChainConfig, cfg.EVMConfig) diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index 951a472e42..480e5cec67 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -44,6 +44,8 @@ type Config struct { Debug bool EVMConfig vm.Config BaseFee *big.Int + BlobHashes []common.Hash + Random *common.Hash State *state.StateDB GetHashFn func(n uint64) common.Hash diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index 7b521a2ead..796d3b4434 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -679,30 +679,30 @@ func TestColdAccountAccessCost(t *testing.T) { func TestRuntimeJSTracer(t *testing.T) { jsTracers := []string{ `{enters: 0, exits: 0, enterGas: 0, gasUsed: 0, steps:0, - step: function() { this.steps++}, - fault: function() {}, - result: function() { - return [this.enters, this.exits,this.enterGas,this.gasUsed, this.steps].join(",") - }, - enter: function(frame) { - this.enters++; + step: function() { this.steps++}, + fault: function() {}, + result: function() { + return [this.enters, this.exits,this.enterGas,this.gasUsed, this.steps].join(",") + }, + enter: function(frame) { + this.enters++; this.enterGas = frame.getGas(); - }, - exit: function(res) { - this.exits++; + }, + exit: function(res) { + this.exits++; this.gasUsed = res.getGasUsed(); }}`, `{enters: 0, exits: 0, enterGas: 0, gasUsed: 0, steps:0, - fault: function() {}, - result: function() { - return [this.enters, this.exits,this.enterGas,this.gasUsed, this.steps].join(",") - }, - enter: function(frame) { - this.enters++; + fault: function() {}, + result: function() { + return [this.enters, this.exits,this.enterGas,this.gasUsed, this.steps].join(",") + }, + enter: function(frame) { + this.enters++; this.enterGas = frame.getGas(); - }, - exit: function(res) { - this.exits++; + }, + exit: function(res) { + this.exits++; this.gasUsed = res.getGasUsed(); }}`} tests := []struct { diff --git a/core/vm/testdata/precompiles/pointEvaluation.json b/core/vm/testdata/precompiles/pointEvaluation.json new file mode 100644 index 0000000000..93fc66d836 --- /dev/null +++ b/core/vm/testdata/precompiles/pointEvaluation.json @@ -0,0 +1,9 @@ +[ + { + "Input": "01d18459b334ffe8e2226eef1db874fda6db2bdd9357268b39220af2d59464fb564c0a11a0f704f4fc3e8acfe0f8245f0ad1347b378fbf96e206da11a5d3630624d25032e67a7e6a4910df5834b8fe70e6bcfeeac0352434196bdf4b2485d5a1978a0d595c823c05947b1156175e72634a377808384256e9921ebf72181890be2d6b58d4a73a880541d1656875654806942307f266e636553e94006d11423f2688945ff3bdf515859eba1005c1a7708d620a94d91a1c0c285f9584e75ec2f82a", + "Expected": "000000000000000000000000000000000000000000000000000000000000100073eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001", + "Name": "pointEvaluation1", + "Gas": 50000, + "NoBenchmark": false + } +] diff --git a/crypto/bls12381/g2.go b/crypto/bls12381/g2.go index 4d6f1ff11d..e5fe75af20 100644 --- a/crypto/bls12381/g2.go +++ b/crypto/bls12381/g2.go @@ -121,7 +121,7 @@ func (g *G2) FromBytes(in []byte) (*PointG2, error) { return p, nil } -// DecodePoint given encoded (x, y) coordinates in 256 bytes returns a valid G1 Point. +// 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") diff --git a/crypto/bn256/cloudflare/optate.go b/crypto/bn256/cloudflare/optate.go index b71e50e3a2..e8caa7a086 100644 --- a/crypto/bn256/cloudflare/optate.go +++ b/crypto/bn256/cloudflare/optate.go @@ -199,9 +199,8 @@ func miller(q *twistPoint, p *curvePoint) *gfP12 { r = newR r2.Square(&minusQ2.y) - a, b, c, newR = lineFunctionAdd(r, minusQ2, bAffine, r2) + a, b, c, _ = lineFunctionAdd(r, minusQ2, bAffine, r2) mulLine(ret, a, b, c) - r = newR return ret } diff --git a/crypto/crypto.go b/crypto/crypto.go index e51b63beca..2492165d38 100644 --- a/crypto/crypto.go +++ b/crypto/crypto.go @@ -141,11 +141,11 @@ func toECDSA(d []byte, strict bool) (*ecdsa.PrivateKey, error) { // The priv.D must < N if priv.D.Cmp(secp256k1N) >= 0 { - return nil, fmt.Errorf("invalid private key, >=N") + return nil, errors.New("invalid private key, >=N") } // The priv.D must not be zero or negative. if priv.D.Sign() <= 0 { - return nil, fmt.Errorf("invalid private key, zero or negative") + return nil, errors.New("invalid private key, zero or negative") } priv.PublicKey.X, priv.PublicKey.Y = priv.PublicKey.Curve.ScalarBaseMult(d) @@ -204,7 +204,7 @@ func LoadECDSA(file string) (*ecdsa.PrivateKey, error) { if err != nil { return nil, err } else if n != len(buf) { - return nil, fmt.Errorf("key file too short, want 64 hex characters") + return nil, errors.New("key file too short, want 64 hex characters") } if err := checkKeyFileEnd(r); err != nil { return nil, err diff --git a/crypto/ecies/ecies.go b/crypto/ecies/ecies.go index 64b5a99d03..738bb8f584 100644 --- a/crypto/ecies/ecies.go +++ b/crypto/ecies/ecies.go @@ -36,18 +36,18 @@ import ( "crypto/hmac" "crypto/subtle" "encoding/binary" - "fmt" + "errors" "hash" "io" "math/big" ) var ( - ErrImport = fmt.Errorf("ecies: failed to import key") - ErrInvalidCurve = fmt.Errorf("ecies: invalid elliptic curve") - ErrInvalidPublicKey = fmt.Errorf("ecies: invalid public key") - ErrSharedKeyIsPointAtInfinity = fmt.Errorf("ecies: shared key is point at infinity") - ErrSharedKeyTooBig = fmt.Errorf("ecies: shared key params are too big") + ErrImport = errors.New("ecies: failed to import key") + ErrInvalidCurve = errors.New("ecies: invalid elliptic curve") + ErrInvalidPublicKey = errors.New("ecies: invalid public key") + ErrSharedKeyIsPointAtInfinity = errors.New("ecies: shared key is point at infinity") + ErrSharedKeyTooBig = errors.New("ecies: shared key params are too big") ) // PublicKey is a representation of an elliptic curve public key. @@ -138,8 +138,8 @@ func (prv *PrivateKey) GenerateShared(pub *PublicKey, skLen, macLen int) (sk []b } var ( - ErrSharedTooLong = fmt.Errorf("ecies: shared secret is too long") - ErrInvalidMessage = fmt.Errorf("ecies: invalid message") + ErrSharedTooLong = errors.New("ecies: shared secret is too long") + ErrInvalidMessage = errors.New("ecies: invalid message") ) // NIST SP 800-56 Concatenation Key Derivation Function (see section 5.8.1). diff --git a/crypto/ecies/ecies_test.go b/crypto/ecies/ecies_test.go index 8ca42c9c8e..e3da71010e 100644 --- a/crypto/ecies/ecies_test.go +++ b/crypto/ecies/ecies_test.go @@ -35,7 +35,7 @@ import ( "crypto/rand" "crypto/sha256" "encoding/hex" - "fmt" + "errors" "math/big" "testing" @@ -62,7 +62,7 @@ func TestKDF(t *testing.T) { } } -var ErrBadSharedKeys = fmt.Errorf("ecies: shared keys don't match") +var ErrBadSharedKeys = errors.New("ecies: shared keys don't match") // cmpParams compares a set of ECIES parameters. We assume, as per the // docs, that AES is the only supported symmetric encryption algorithm. diff --git a/crypto/ecies/params.go b/crypto/ecies/params.go index 39e7c89473..df7698ea0c 100644 --- a/crypto/ecies/params.go +++ b/crypto/ecies/params.go @@ -39,6 +39,7 @@ import ( "crypto/elliptic" "crypto/sha256" "crypto/sha512" + "errors" "fmt" "hash" @@ -47,8 +48,8 @@ import ( var ( DefaultCurve = ethcrypto.S256() - ErrUnsupportedECDHAlgorithm = fmt.Errorf("ecies: unsupported ECDH algorithm") - ErrUnsupportedECIESParameters = fmt.Errorf("ecies: unsupported ECIES parameters") + ErrUnsupportedECDHAlgorithm = errors.New("ecies: unsupported ECDH algorithm") + ErrUnsupportedECIESParameters = errors.New("ecies: unsupported ECIES parameters") ErrInvalidKeyLen = fmt.Errorf("ecies: invalid key size (> %d) in ECIESParams", maxKeyLen) ) diff --git a/crypto/kzg4844/kzg4844.go b/crypto/kzg4844/kzg4844.go index 3bd814159d..5969d1c2ce 100644 --- a/crypto/kzg4844/kzg4844.go +++ b/crypto/kzg4844/kzg4844.go @@ -54,7 +54,7 @@ func UseCKZG(use bool) error { useCKZG.Store(use) // Initializing the library can take 2-4 seconds - and can potentially crash - // on CKZG and non-ADX CPUs - so might as well so it now and don't wait until + // on CKZG and non-ADX CPUs - so might as well do it now and don't wait until // a crypto operation is actually needed live. if use { ckzgIniter.Do(ckzgInit) diff --git a/crypto/kzg4844/kzg4844_ckzg_cgo.go b/crypto/kzg4844/kzg4844_ckzg_cgo.go index d62ca3fad6..5400285698 100644 --- a/crypto/kzg4844/kzg4844_ckzg_cgo.go +++ b/crypto/kzg4844/kzg4844_ckzg_cgo.go @@ -74,6 +74,8 @@ 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) { + ckzgIniter.Do(ckzgInit) + proof, claim, err := ckzg4844.ComputeKZGProof((ckzg4844.Blob)(blob), (ckzg4844.Bytes32)(point)) if err != nil { return Proof{}, Claim{}, err @@ -84,6 +86,8 @@ func ckzgComputeProof(blob Blob, point Point) (Proof, Claim, error) { // ckzgVerifyProof verifies the KZG proof that the polynomial represented by the blob // evaluated at the given point is the claimed value. func ckzgVerifyProof(commitment Commitment, point Point, claim Claim, proof Proof) error { + ckzgIniter.Do(ckzgInit) + valid, err := ckzg4844.VerifyKZGProof((ckzg4844.Bytes48)(commitment), (ckzg4844.Bytes32)(point), (ckzg4844.Bytes32)(claim), (ckzg4844.Bytes48)(proof)) if err != nil { return err @@ -99,6 +103,8 @@ func ckzgVerifyProof(commitment Commitment, point Point, claim Claim, proof Proo // // This method does not verify that the commitment is correct with respect to blob. func ckzgComputeBlobProof(blob Blob, commitment Commitment) (Proof, error) { + ckzgIniter.Do(ckzgInit) + proof, err := ckzg4844.ComputeBlobKZGProof((ckzg4844.Blob)(blob), (ckzg4844.Bytes48)(commitment)) if err != nil { return Proof{}, err @@ -108,6 +114,8 @@ 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 { + ckzgIniter.Do(ckzgInit) + valid, err := ckzg4844.VerifyBlobKZGProof((ckzg4844.Blob)(blob), (ckzg4844.Bytes48)(commitment), (ckzg4844.Bytes48)(proof)) if err != nil { return err diff --git a/crypto/kzg4844/kzg4844_test.go b/crypto/kzg4844/kzg4844_test.go index 0d35667a9c..fae8a7a76e 100644 --- a/crypto/kzg4844/kzg4844_test.go +++ b/crypto/kzg4844/kzg4844_test.go @@ -47,7 +47,6 @@ func randBlob() Blob { func TestCKZGWithPoint(t *testing.T) { testKZGWithPoint(t, true) } func TestGoKZGWithPoint(t *testing.T) { testKZGWithPoint(t, false) } - func testKZGWithPoint(t *testing.T, ckzg bool) { if ckzg && !ckzgAvailable { t.Skip("CKZG unavailable in this test build") @@ -73,7 +72,6 @@ func testKZGWithPoint(t *testing.T, ckzg bool) { func TestCKZGWithBlob(t *testing.T) { testKZGWithBlob(t, true) } func TestGoKZGWithBlob(t *testing.T) { testKZGWithBlob(t, false) } - func testKZGWithBlob(t *testing.T, ckzg bool) { if ckzg && !ckzgAvailable { t.Skip("CKZG unavailable in this test build") @@ -106,6 +104,8 @@ func benchmarkBlobToCommitment(b *testing.B, ckzg bool) { useCKZG.Store(ckzg) blob := randBlob() + + b.ResetTimer() for i := 0; i < b.N; i++ { BlobToCommitment(blob) } @@ -124,6 +124,8 @@ func benchmarkComputeProof(b *testing.B, ckzg bool) { blob = randBlob() point = randFieldElement() ) + + b.ResetTimer() for i := 0; i < b.N; i++ { ComputeProof(blob, point) } @@ -144,6 +146,8 @@ func benchmarkVerifyProof(b *testing.B, ckzg bool) { commitment, _ = BlobToCommitment(blob) proof, claim, _ = ComputeProof(blob, point) ) + + b.ResetTimer() for i := 0; i < b.N; i++ { VerifyProof(commitment, point, claim, proof) } @@ -162,6 +166,8 @@ func benchmarkComputeBlobProof(b *testing.B, ckzg bool) { blob = randBlob() commitment, _ = BlobToCommitment(blob) ) + + b.ResetTimer() for i := 0; i < b.N; i++ { ComputeBlobProof(blob, commitment) } @@ -181,6 +187,8 @@ func benchmarkVerifyBlobProof(b *testing.B, ckzg bool) { commitment, _ = BlobToCommitment(blob) proof, _ = ComputeBlobProof(blob, commitment) ) + + b.ResetTimer() for i := 0; i < b.N; i++ { VerifyBlobProof(blob, commitment, proof) } diff --git a/crypto/secp256k1/secp256.go b/crypto/secp256k1/secp256.go index c9c01b3209..61abc1eaf0 100644 --- a/crypto/secp256k1/secp256.go +++ b/crypto/secp256k1/secp256.go @@ -21,11 +21,14 @@ package secp256k1 # define USE_SCALAR_8X32 #endif +#ifndef NDEBUG +# define NDEBUG +#endif + #define USE_ENDOMORPHISM #define USE_NUM_NONE #define USE_FIELD_INV_BUILTIN #define USE_SCALAR_INV_BUILTIN -#define NDEBUG #include "./libsecp256k1/src/secp256k1.c" #include "./libsecp256k1/src/modules/recovery/main_impl.h" #include "ext.h" diff --git a/crypto/signature_cgo.go b/crypto/signature_cgo.go index 3a32755f5e..2339e52015 100644 --- a/crypto/signature_cgo.go +++ b/crypto/signature_cgo.go @@ -22,6 +22,7 @@ package crypto import ( "crypto/ecdsa" "crypto/elliptic" + "errors" "fmt" "github.com/ethereum/go-ethereum/common/math" @@ -72,7 +73,7 @@ func VerifySignature(pubkey, digestHash, signature []byte) bool { func DecompressPubkey(pubkey []byte) (*ecdsa.PublicKey, error) { x, y := secp256k1.DecompressPubkey(pubkey) if x == nil { - return nil, fmt.Errorf("invalid public key") + return nil, errors.New("invalid public key") } return &ecdsa.PublicKey{X: x, Y: y, Curve: S256()}, nil } diff --git a/crypto/signature_nocgo.go b/crypto/signature_nocgo.go index 3e48e51e84..6d628d758d 100644 --- a/crypto/signature_nocgo.go +++ b/crypto/signature_nocgo.go @@ -74,12 +74,12 @@ func Sign(hash []byte, prv *ecdsa.PrivateKey) ([]byte, error) { return nil, fmt.Errorf("hash is required to be exactly 32 bytes (%d)", len(hash)) } if prv.Curve != btcec.S256() { - return nil, fmt.Errorf("private key curve is not secp256k1") + return nil, errors.New("private key curve is not secp256k1") } // ecdsa.PrivateKey -> btcec.PrivateKey var priv btcec.PrivateKey if overflow := priv.Key.SetByteSlice(prv.D.Bytes()); overflow || priv.Key.IsZero() { - return nil, fmt.Errorf("invalid private key") + return nil, errors.New("invalid private key") } defer priv.Zero() sig, err := btc_ecdsa.SignCompact(&priv, hash, false) // ref uncompressed pubkey diff --git a/eth/api.go b/eth/api.go index 5fdd0117dd..44e934fd04 100644 --- a/eth/api.go +++ b/eth/api.go @@ -17,27 +17,8 @@ package eth import ( - "compress/gzip" - "context" - "errors" - "fmt" - "io" - "math/big" - "os" - "strings" - "time" - "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/state" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/internal/ethapi" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rlp" - "github.com/ethereum/go-ethereum/rpc" - "github.com/ethereum/go-ethereum/trie" ) // EthereumAPI provides an API to access Ethereum full node-related information. @@ -50,12 +31,12 @@ func NewEthereumAPI(e *Ethereum) *EthereumAPI { return &EthereumAPI{e} } -// Etherbase is the address that mining rewards will be send to. +// 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 send to (alias for 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() } @@ -69,542 +50,3 @@ func (api *EthereumAPI) Hashrate() hexutil.Uint64 { func (api *EthereumAPI) Mining() bool { return api.e.IsMining() } - -// MinerAPI provides an API to control the miner. -type MinerAPI struct { - e *Ethereum -} - -// NewMinerAPI create a new MinerAPI instance. -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 { - return false, err - } - return true, nil -} - -// SetGasPrice sets the minimum accepted gas price for the miner. -func (api *MinerAPI) SetGasPrice(gasPrice hexutil.Big) bool { - api.e.lock.Lock() - api.e.gasPrice = (*big.Int)(&gasPrice) - api.e.lock.Unlock() - - api.e.txPool.SetGasPrice((*big.Int)(&gasPrice)) - return true -} - -// SetGasLimit sets the gaslimit to target towards during mining. -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) -} - -// AdminAPI is the collection of Ethereum full node related APIs for node -// administration. -type AdminAPI struct { - eth *Ethereum -} - -// NewAdminAPI creates a new instance of AdminAPI. -func NewAdminAPI(eth *Ethereum) *AdminAPI { - return &AdminAPI{eth: eth} -} - -// ExportChain exports the current blockchain into a local file, -// or a range of blocks if first and last are non-nil. -func (api *AdminAPI) ExportChain(file string, first *uint64, last *uint64) (bool, error) { - if first == nil && last != nil { - return false, errors.New("last cannot be specified without first") - } - if first != nil && last == nil { - head := api.eth.BlockChain().CurrentHeader().Number.Uint64() - last = &head - } - if _, err := os.Stat(file); err == nil { - // File already exists. Allowing overwrite could be a DoS vector, - // since the 'file' may point to arbitrary paths on the drive. - return false, errors.New("location would overwrite an existing file") - } - // Make sure we can create the file to export into - out, err := os.OpenFile(file, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644) - if err != nil { - return false, err - } - defer out.Close() - - var writer io.Writer = out - if strings.HasSuffix(file, ".gz") { - writer = gzip.NewWriter(writer) - defer writer.(*gzip.Writer).Close() - } - - // Export the blockchain - if first != nil { - if err := api.eth.BlockChain().ExportN(writer, *first, *last); err != nil { - return false, err - } - } else if err := api.eth.BlockChain().Export(writer); err != nil { - return false, err - } - return true, nil -} - -func hasAllBlocks(chain *core.BlockChain, bs []*types.Block) bool { - for _, b := range bs { - if !chain.HasBlock(b.Hash(), b.NumberU64()) { - return false - } - } - - return true -} - -// ImportChain imports a blockchain from a local file. -func (api *AdminAPI) ImportChain(file string) (bool, error) { - // Make sure the can access the file to import - in, err := os.Open(file) - if err != nil { - return false, err - } - defer in.Close() - - var reader io.Reader = in - if strings.HasSuffix(file, ".gz") { - if reader, err = gzip.NewReader(reader); err != nil { - return false, err - } - } - - // Run actual the import in pre-configured batches - stream := rlp.NewStream(reader, 0) - - blocks, index := make([]*types.Block, 0, 2500), 0 - for batch := 0; ; batch++ { - // Load a batch of blocks from the input file - for len(blocks) < cap(blocks) { - block := new(types.Block) - if err := stream.Decode(block); err == io.EOF { - break - } else if err != nil { - return false, fmt.Errorf("block %d: failed to parse: %v", index, err) - } - blocks = append(blocks, block) - index++ - } - if len(blocks) == 0 { - break - } - - if hasAllBlocks(api.eth.BlockChain(), blocks) { - blocks = blocks[:0] - continue - } - // Import the batch and reset the buffer - if _, err := api.eth.BlockChain().InsertChain(blocks); err != nil { - return false, fmt.Errorf("batch %d: failed to insert: %v", batch, err) - } - blocks = blocks[:0] - } - return true, nil -} - -// DebugAPI is the collection of Ethereum full node APIs for debugging the -// protocol. -type DebugAPI struct { - eth *Ethereum -} - -// NewDebugAPI creates a new DebugAPI instance. -func NewDebugAPI(eth *Ethereum) *DebugAPI { - return &DebugAPI{eth: eth} -} - -// DumpBlock retrieves the entire state of the database at a given block. -func (api *DebugAPI) DumpBlock(blockNr rpc.BlockNumber) (state.Dump, error) { - opts := &state.DumpConfig{ - OnlyWithAddresses: true, - Max: AccountRangeMaxResults, // Sanity limit over RPC - } - if blockNr == rpc.PendingBlockNumber { - // 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() - return stateDb.RawDump(opts), nil - } - var header *types.Header - if blockNr == rpc.LatestBlockNumber { - header = api.eth.blockchain.CurrentBlock() - } else if blockNr == rpc.FinalizedBlockNumber { - header = api.eth.blockchain.CurrentFinalBlock() - } else if blockNr == rpc.SafeBlockNumber { - header = api.eth.blockchain.CurrentSafeBlock() - } else { - block := api.eth.blockchain.GetBlockByNumber(uint64(blockNr)) - if block == nil { - return state.Dump{}, fmt.Errorf("block #%d not found", blockNr) - } - header = block.Header() - } - if header == nil { - return state.Dump{}, fmt.Errorf("block #%d not found", blockNr) - } - stateDb, err := api.eth.BlockChain().StateAt(header.Root) - if err != nil { - return state.Dump{}, err - } - return stateDb.RawDump(opts), nil -} - -// Preimage is a debug API function that returns the preimage for a sha3 hash, if known. -func (api *DebugAPI) Preimage(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) { - if preimage := rawdb.ReadPreimage(api.eth.ChainDb(), hash); preimage != nil { - return preimage, nil - } - return nil, errors.New("unknown preimage") -} - -// BadBlockArgs represents the entries in the list returned when bad blocks are queried. -type BadBlockArgs struct { - Hash common.Hash `json:"hash"` - Block map[string]interface{} `json:"block"` - RLP string `json:"rlp"` -} - -// GetBadBlocks returns a list of the last 'bad blocks' that the client has seen on the network -// and returns them as a JSON list of block hashes. -func (api *DebugAPI) GetBadBlocks(ctx context.Context) ([]*BadBlockArgs, error) { - var ( - err error - blocks = rawdb.ReadAllBadBlocks(api.eth.chainDb) - results = make([]*BadBlockArgs, 0, len(blocks)) - ) - for _, block := range blocks { - var ( - blockRlp string - blockJSON map[string]interface{} - ) - if rlpBytes, err := rlp.EncodeToBytes(block); err != nil { - blockRlp = err.Error() // Hacky, but hey, it works - } else { - blockRlp = fmt.Sprintf("%#x", rlpBytes) - } - if blockJSON, err = ethapi.RPCMarshalBlock(block, true, true, api.eth.APIBackend.ChainConfig()); err != nil { - blockJSON = map[string]interface{}{"error": err.Error()} - } - results = append(results, &BadBlockArgs{ - Hash: block.Hash(), - RLP: blockRlp, - Block: blockJSON, - }) - } - return results, nil -} - -// AccountRangeMaxResults is the maximum number of results to be returned per call -const AccountRangeMaxResults = 256 - -// AccountRange enumerates all accounts in the given block and start point in paging request -func (api *DebugAPI) AccountRange(blockNrOrHash rpc.BlockNumberOrHash, start hexutil.Bytes, maxResults int, nocode, nostorage, incompletes bool) (state.IteratorDump, error) { - var stateDb *state.StateDB - var err error - - if number, ok := blockNrOrHash.Number(); ok { - if number == rpc.PendingBlockNumber { - // 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() - } else { - var header *types.Header - if number == rpc.LatestBlockNumber { - header = api.eth.blockchain.CurrentBlock() - } else if number == rpc.FinalizedBlockNumber { - header = api.eth.blockchain.CurrentFinalBlock() - } else if number == rpc.SafeBlockNumber { - header = api.eth.blockchain.CurrentSafeBlock() - } else { - block := api.eth.blockchain.GetBlockByNumber(uint64(number)) - if block == nil { - return state.IteratorDump{}, fmt.Errorf("block #%d not found", number) - } - header = block.Header() - } - if header == nil { - return state.IteratorDump{}, fmt.Errorf("block #%d not found", number) - } - stateDb, err = api.eth.BlockChain().StateAt(header.Root) - if err != nil { - return state.IteratorDump{}, err - } - } - } else if hash, ok := blockNrOrHash.Hash(); ok { - block := api.eth.blockchain.GetBlockByHash(hash) - if block == nil { - return state.IteratorDump{}, fmt.Errorf("block %s not found", hash.Hex()) - } - stateDb, err = api.eth.BlockChain().StateAt(block.Root()) - if err != nil { - return state.IteratorDump{}, err - } - } else { - return state.IteratorDump{}, errors.New("either block number or block hash must be specified") - } - - opts := &state.DumpConfig{ - SkipCode: nocode, - SkipStorage: nostorage, - OnlyWithAddresses: !incompletes, - Start: start, - Max: uint64(maxResults), - } - if maxResults > AccountRangeMaxResults || maxResults <= 0 { - opts.Max = AccountRangeMaxResults - } - return stateDb.IteratorDump(opts), nil -} - -// StorageRangeResult is the result of a debug_storageRangeAt API call. -type StorageRangeResult struct { - Storage storageMap `json:"storage"` - NextKey *common.Hash `json:"nextKey"` // nil if Storage includes the last key in the trie. -} - -type storageMap map[common.Hash]storageEntry - -type storageEntry struct { - Key *common.Hash `json:"key"` - Value common.Hash `json:"value"` -} - -// StorageRangeAt returns the storage at the given block height and transaction index. -func (api *DebugAPI) StorageRangeAt(ctx context.Context, blockHash common.Hash, txIndex int, contractAddress common.Address, keyStart hexutil.Bytes, maxResult int) (StorageRangeResult, error) { - // Retrieve the block - block := api.eth.blockchain.GetBlockByHash(blockHash) - if block == nil { - return StorageRangeResult{}, fmt.Errorf("block %#x not found", blockHash) - } - _, _, statedb, release, err := api.eth.stateAtTransaction(ctx, block, txIndex, 0) - if err != nil { - return StorageRangeResult{}, err - } - defer release() - - st, err := statedb.StorageTrie(contractAddress) - if err != nil { - return StorageRangeResult{}, err - } - if st == nil { - return StorageRangeResult{}, fmt.Errorf("account %x doesn't exist", contractAddress) - } - return storageRangeAt(st, keyStart, maxResult) -} - -func storageRangeAt(st state.Trie, start []byte, maxResult int) (StorageRangeResult, error) { - it := trie.NewIterator(st.NodeIterator(start)) - result := StorageRangeResult{Storage: storageMap{}} - for i := 0; i < maxResult && it.Next(); i++ { - _, content, _, err := rlp.Split(it.Value) - if err != nil { - return StorageRangeResult{}, err - } - e := storageEntry{Value: common.BytesToHash(content)} - if preimage := st.GetKey(it.Key); preimage != nil { - preimage := common.BytesToHash(preimage) - e.Key = &preimage - } - result.Storage[common.BytesToHash(it.Key)] = e - } - // Add the 'next key' so clients can continue downloading. - if it.Next() { - next := common.BytesToHash(it.Key) - result.NextKey = &next - } - return result, nil -} - -// GetModifiedAccountsByNumber returns all accounts that have changed between the -// two blocks specified. A change is defined as a difference in nonce, balance, -// code hash, or storage hash. -// -// With one parameter, returns the list of accounts modified in the specified block. -func (api *DebugAPI) GetModifiedAccountsByNumber(startNum uint64, endNum *uint64) ([]common.Address, error) { - var startBlock, endBlock *types.Block - - startBlock = api.eth.blockchain.GetBlockByNumber(startNum) - if startBlock == nil { - return nil, fmt.Errorf("start block %x not found", startNum) - } - - if endNum == nil { - endBlock = startBlock - startBlock = api.eth.blockchain.GetBlockByHash(startBlock.ParentHash()) - if startBlock == nil { - return nil, fmt.Errorf("block %x has no parent", endBlock.Number()) - } - } else { - endBlock = api.eth.blockchain.GetBlockByNumber(*endNum) - if endBlock == nil { - return nil, fmt.Errorf("end block %d not found", *endNum) - } - } - return api.getModifiedAccounts(startBlock, endBlock) -} - -// GetModifiedAccountsByHash returns all accounts that have changed between the -// two blocks specified. A change is defined as a difference in nonce, balance, -// code hash, or storage hash. -// -// With one parameter, returns the list of accounts modified in the specified block. -func (api *DebugAPI) GetModifiedAccountsByHash(startHash common.Hash, endHash *common.Hash) ([]common.Address, error) { - var startBlock, endBlock *types.Block - startBlock = api.eth.blockchain.GetBlockByHash(startHash) - if startBlock == nil { - return nil, fmt.Errorf("start block %x not found", startHash) - } - - if endHash == nil { - endBlock = startBlock - startBlock = api.eth.blockchain.GetBlockByHash(startBlock.ParentHash()) - if startBlock == nil { - return nil, fmt.Errorf("block %x has no parent", endBlock.Number()) - } - } else { - endBlock = api.eth.blockchain.GetBlockByHash(*endHash) - if endBlock == nil { - return nil, fmt.Errorf("end block %x not found", *endHash) - } - } - return api.getModifiedAccounts(startBlock, endBlock) -} - -func (api *DebugAPI) getModifiedAccounts(startBlock, endBlock *types.Block) ([]common.Address, error) { - if startBlock.Number().Uint64() >= endBlock.Number().Uint64() { - return nil, fmt.Errorf("start block height (%d) must be less than end block height (%d)", startBlock.Number().Uint64(), endBlock.Number().Uint64()) - } - triedb := api.eth.BlockChain().StateCache().TrieDB() - - oldTrie, err := trie.NewStateTrie(trie.StateTrieID(startBlock.Root()), triedb) - if err != nil { - return nil, err - } - newTrie, err := trie.NewStateTrie(trie.StateTrieID(endBlock.Root()), triedb) - if err != nil { - return nil, err - } - diff, _ := trie.NewDifferenceIterator(oldTrie.NodeIterator([]byte{}), newTrie.NodeIterator([]byte{})) - iter := trie.NewIterator(diff) - - var dirty []common.Address - for iter.Next() { - key := newTrie.GetKey(iter.Key) - if key == nil { - return nil, fmt.Errorf("no preimage found for hash %x", iter.Key) - } - dirty = append(dirty, common.BytesToAddress(key)) - } - return dirty, nil -} - -// GetAccessibleState returns the first number where the node has accessible -// state on disk. Note this being the post-state of that block and the pre-state -// of the next block. -// The (from, to) parameters are the sequence of blocks to search, which can go -// either forwards or backwards -func (api *DebugAPI) GetAccessibleState(from, to rpc.BlockNumber) (uint64, error) { - db := api.eth.ChainDb() - var pivot uint64 - if p := rawdb.ReadLastPivotNumber(db); p != nil { - pivot = *p - log.Info("Found fast-sync pivot marker", "number", pivot) - } - var resolveNum = func(num rpc.BlockNumber) (uint64, error) { - // We don't have state for pending (-2), so treat it as latest - if num.Int64() < 0 { - block := api.eth.blockchain.CurrentBlock() - if block == nil { - return 0, fmt.Errorf("current block missing") - } - return block.Number.Uint64(), nil - } - return uint64(num.Int64()), nil - } - var ( - start uint64 - end uint64 - delta = int64(1) - lastLog time.Time - err error - ) - if start, err = resolveNum(from); err != nil { - return 0, err - } - if end, err = resolveNum(to); err != nil { - return 0, err - } - if start == end { - return 0, fmt.Errorf("from and to needs to be different") - } - if start > end { - delta = -1 - } - for i := int64(start); i != int64(end); i += delta { - if time.Since(lastLog) > 8*time.Second { - log.Info("Finding roots", "from", start, "to", end, "at", i) - lastLog = time.Now() - } - if i < int64(pivot) { - continue - } - h := api.eth.BlockChain().GetHeaderByNumber(uint64(i)) - if h == nil { - return 0, fmt.Errorf("missing header %d", i) - } - if ok, _ := api.eth.ChainDb().Has(h.Root[:]); ok { - return uint64(i), nil - } - } - return 0, errors.New("no state found") -} - -// SetTrieFlushInterval configures how often in-memory tries are persisted -// to disk. The value is in terms of block processing time, not wall clock. -func (api *DebugAPI) SetTrieFlushInterval(interval string) error { - t, err := time.ParseDuration(interval) - if err != nil { - return err - } - api.eth.blockchain.SetTrieFlushInterval(t) - return nil -} diff --git a/eth/api_admin.go b/eth/api_admin.go new file mode 100644 index 0000000000..4a3ccb84e8 --- /dev/null +++ b/eth/api_admin.go @@ -0,0 +1,143 @@ +// 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 eth + +import ( + "compress/gzip" + "errors" + "fmt" + "io" + "os" + "strings" + + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/rlp" +) + +// AdminAPI is the collection of Ethereum full node related APIs for node +// administration. +type AdminAPI struct { + eth *Ethereum +} + +// NewAdminAPI creates a new instance of AdminAPI. +func NewAdminAPI(eth *Ethereum) *AdminAPI { + return &AdminAPI{eth: eth} +} + +// ExportChain exports the current blockchain into a local file, +// or a range of blocks if first and last are non-nil. +func (api *AdminAPI) ExportChain(file string, first *uint64, last *uint64) (bool, error) { + if first == nil && last != nil { + return false, errors.New("last cannot be specified without first") + } + if first != nil && last == nil { + head := api.eth.BlockChain().CurrentHeader().Number.Uint64() + last = &head + } + if _, err := os.Stat(file); err == nil { + // File already exists. Allowing overwrite could be a DoS vector, + // since the 'file' may point to arbitrary paths on the drive. + return false, errors.New("location would overwrite an existing file") + } + // Make sure we can create the file to export into + out, err := os.OpenFile(file, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644) + if err != nil { + return false, err + } + defer out.Close() + + var writer io.Writer = out + if strings.HasSuffix(file, ".gz") { + writer = gzip.NewWriter(writer) + defer writer.(*gzip.Writer).Close() + } + + // Export the blockchain + if first != nil { + if err := api.eth.BlockChain().ExportN(writer, *first, *last); err != nil { + return false, err + } + } else if err := api.eth.BlockChain().Export(writer); err != nil { + return false, err + } + return true, nil +} + +func hasAllBlocks(chain *core.BlockChain, bs []*types.Block) bool { + for _, b := range bs { + if !chain.HasBlock(b.Hash(), b.NumberU64()) { + return false + } + } + + return true +} + +// ImportChain imports a blockchain from a local file. +func (api *AdminAPI) ImportChain(file string) (bool, error) { + // Make sure the can access the file to import + in, err := os.Open(file) + if err != nil { + return false, err + } + defer in.Close() + + var reader io.Reader = in + if strings.HasSuffix(file, ".gz") { + if reader, err = gzip.NewReader(reader); err != nil { + return false, err + } + } + + // Run actual the import in pre-configured batches + stream := rlp.NewStream(reader, 0) + + blocks, index := make([]*types.Block, 0, 2500), 0 + for batch := 0; ; batch++ { + // Load a batch of blocks from the input file + for len(blocks) < cap(blocks) { + block := new(types.Block) + if err := stream.Decode(block); err == io.EOF { + break + } else if err != nil { + return false, fmt.Errorf("block %d: failed to parse: %v", index, err) + } + // ignore the genesis block when importing blocks + if block.NumberU64() == 0 { + continue + } + blocks = append(blocks, block) + index++ + } + if len(blocks) == 0 { + break + } + + if hasAllBlocks(api.eth.BlockChain(), blocks) { + blocks = blocks[:0] + continue + } + // Import the batch and reset the buffer + if _, err := api.eth.BlockChain().InsertChain(blocks); err != nil { + return false, fmt.Errorf("batch %d: failed to insert: %v", batch, err) + } + blocks = blocks[:0] + } + return true, nil +} diff --git a/eth/api_backend.go b/eth/api_backend.go index 1789f106e9..dea745382e 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -42,7 +42,7 @@ import ( "github.com/ethereum/go-ethereum/rpc" ) -// EthAPIBackend implements ethapi.Backend for full nodes +// EthAPIBackend implements ethapi.Backend and tracers.Backend for full nodes type EthAPIBackend struct { extRPCEnabled bool allowUnprotectedTxs bool @@ -68,6 +68,9 @@ func (b *EthAPIBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumb // Pending block is only known by the miner if number == rpc.PendingBlockNumber { block := b.eth.miner.PendingBlock() + if block == nil { + return nil, errors.New("pending block is not available") + } return block.Header(), nil } // Otherwise resolve and return the block @@ -75,24 +78,18 @@ func (b *EthAPIBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumb return b.eth.blockchain.CurrentBlock(), nil } if number == rpc.FinalizedBlockNumber { - if !b.eth.Merger().TDDReached() { - return nil, errors.New("'finalized' tag not supported on pre-merge network") - } block := b.eth.blockchain.CurrentFinalBlock() - if block != nil { - return block, nil + if block == nil { + return nil, errors.New("finalized block not found") } - return nil, errors.New("finalized block not found") + return block, nil } if number == rpc.SafeBlockNumber { - if !b.eth.Merger().TDDReached() { - return nil, errors.New("'safe' tag not supported on pre-merge network") - } block := b.eth.blockchain.CurrentSafeBlock() - if block != nil { - return block, nil + if block == nil { + return nil, errors.New("safe block not found") } - return nil, errors.New("safe block not found") + return block, nil } return b.eth.blockchain.GetHeaderByNumber(uint64(number)), nil } @@ -122,6 +119,9 @@ func (b *EthAPIBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumbe // Pending block is only known by the miner if number == rpc.PendingBlockNumber { block := b.eth.miner.PendingBlock() + if block == nil { + return nil, errors.New("pending block is not available") + } return block, nil } // Otherwise resolve and return the block @@ -130,9 +130,6 @@ func (b *EthAPIBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumbe return b.eth.blockchain.GetBlock(header.Hash(), header.Number.Uint64()), nil } if number == rpc.FinalizedBlockNumber { - if !b.eth.Merger().TDDReached() { - return nil, errors.New("'finalized' tag not supported on pre-merge network") - } header := b.eth.blockchain.CurrentFinalBlock() if header == nil { return nil, errors.New("finalized block not found") @@ -140,9 +137,6 @@ func (b *EthAPIBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumbe return b.eth.blockchain.GetBlock(header.Hash(), header.Number.Uint64()), nil } if number == rpc.SafeBlockNumber { - if !b.eth.Merger().TDDReached() { - return nil, errors.New("'safe' tag not supported on pre-merge network") - } header := b.eth.blockchain.CurrentSafeBlock() if header == nil { return nil, errors.New("safe block not found") @@ -196,6 +190,9 @@ func (b *EthAPIBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.B // Pending state is only known by the miner if number == rpc.PendingBlockNumber { block, state := b.eth.miner.Pending() + if block == nil || state == nil { + return nil, nil, errors.New("pending state is not available") + } return state, block.Header(), nil } // Otherwise resolve the block number and return its state @@ -236,7 +233,7 @@ func (b *EthAPIBackend) GetReceipts(ctx context.Context, hash common.Hash) (type } func (b *EthAPIBackend) GetLogs(ctx context.Context, hash common.Hash, number uint64) ([][]*types.Log, error) { - return rawdb.ReadLogs(b.eth.chainDb, hash, number, b.ChainConfig()), nil + return rawdb.ReadLogs(b.eth.chainDb, hash, number), nil } func (b *EthAPIBackend) GetTd(ctx context.Context, hash common.Hash) *big.Int { @@ -285,14 +282,18 @@ func (b *EthAPIBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscri } func (b *EthAPIBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error { - return b.eth.txPool.AddLocal(signedTx) + return b.eth.txPool.Add([]*types.Transaction{signedTx}, true, false)[0] } func (b *EthAPIBackend) GetPoolTransactions() (types.Transactions, error) { pending := b.eth.txPool.Pending(false) var txs types.Transactions for _, batch := range pending { - txs = append(txs, batch...) + for _, lazy := range batch { + if tx := lazy.Resolve(); tx != nil { + txs = append(txs, tx) + } + } } return txs, nil } @@ -310,24 +311,24 @@ func (b *EthAPIBackend) GetPoolNonce(ctx context.Context, addr common.Address) ( return b.eth.txPool.Nonce(addr), nil } -func (b *EthAPIBackend) Stats() (pending int, queued int) { +func (b *EthAPIBackend) Stats() (runnable int, blocked int) { return b.eth.txPool.Stats() } -func (b *EthAPIBackend) TxPoolContent() (map[common.Address]types.Transactions, map[common.Address]types.Transactions) { - return b.eth.TxPool().Content() +func (b *EthAPIBackend) TxPoolContent() (map[common.Address][]*types.Transaction, map[common.Address][]*types.Transaction) { + return b.eth.txPool.Content() } -func (b *EthAPIBackend) TxPoolContentFrom(addr common.Address) (types.Transactions, types.Transactions) { - return b.eth.TxPool().ContentFrom(addr) +func (b *EthAPIBackend) TxPoolContentFrom(addr common.Address) ([]*types.Transaction, []*types.Transaction) { + return b.eth.txPool.ContentFrom(addr) } func (b *EthAPIBackend) TxPool() *txpool.TxPool { - return b.eth.TxPool() + return b.eth.txPool } func (b *EthAPIBackend) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription { - return b.eth.TxPool().SubscribeNewTxsEvent(ch) + return b.eth.txPool.SubscribeNewTxsEvent(ch) } func (b *EthAPIBackend) SyncProgress() ethereum.SyncProgress { @@ -402,7 +403,7 @@ func (b *EthAPIBackend) StartMining() error { } 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) + 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) { diff --git a/eth/api_debug.go b/eth/api_debug.go new file mode 100644 index 0000000000..22dd6b0cf7 --- /dev/null +++ b/eth/api_debug.go @@ -0,0 +1,436 @@ +// 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 eth + +import ( + "context" + "errors" + "fmt" + "time" + + "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/crypto" + "github.com/ethereum/go-ethereum/internal/ethapi" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-ethereum/rpc" + "github.com/ethereum/go-ethereum/trie" +) + +// DebugAPI is the collection of Ethereum full node APIs for debugging the +// protocol. +type DebugAPI struct { + eth *Ethereum +} + +// NewDebugAPI creates a new DebugAPI instance. +func NewDebugAPI(eth *Ethereum) *DebugAPI { + return &DebugAPI{eth: eth} +} + +// DumpBlock retrieves the entire state of the database at a given block. +func (api *DebugAPI) DumpBlock(blockNr rpc.BlockNumber) (state.Dump, error) { + opts := &state.DumpConfig{ + OnlyWithAddresses: true, + Max: AccountRangeMaxResults, // Sanity limit over RPC + } + if blockNr == rpc.PendingBlockNumber { + // 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() + if stateDb == nil { + return state.Dump{}, errors.New("pending state is not available") + } + return stateDb.RawDump(opts), nil + } + var header *types.Header + switch blockNr { + case rpc.LatestBlockNumber: + header = api.eth.blockchain.CurrentBlock() + case rpc.FinalizedBlockNumber: + header = api.eth.blockchain.CurrentFinalBlock() + case rpc.SafeBlockNumber: + header = api.eth.blockchain.CurrentSafeBlock() + default: + block := api.eth.blockchain.GetBlockByNumber(uint64(blockNr)) + if block == nil { + return state.Dump{}, fmt.Errorf("block #%d not found", blockNr) + } + header = block.Header() + } + if header == nil { + return state.Dump{}, fmt.Errorf("block #%d not found", blockNr) + } + stateDb, err := api.eth.BlockChain().StateAt(header.Root) + if err != nil { + return state.Dump{}, err + } + return stateDb.RawDump(opts), nil +} + +// Preimage is a debug API function that returns the preimage for a sha3 hash, if known. +func (api *DebugAPI) Preimage(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) { + if preimage := rawdb.ReadPreimage(api.eth.ChainDb(), hash); preimage != nil { + return preimage, nil + } + return nil, errors.New("unknown preimage") +} + +// BadBlockArgs represents the entries in the list returned when bad blocks are queried. +type BadBlockArgs struct { + Hash common.Hash `json:"hash"` + Block map[string]interface{} `json:"block"` + RLP string `json:"rlp"` +} + +// GetBadBlocks returns a list of the last 'bad blocks' that the client has seen on the network +// and returns them as a JSON list of block hashes. +func (api *DebugAPI) GetBadBlocks(ctx context.Context) ([]*BadBlockArgs, error) { + var ( + blocks = rawdb.ReadAllBadBlocks(api.eth.chainDb) + results = make([]*BadBlockArgs, 0, len(blocks)) + ) + for _, block := range blocks { + var ( + blockRlp string + blockJSON map[string]interface{} + ) + if rlpBytes, err := rlp.EncodeToBytes(block); err != nil { + blockRlp = err.Error() // Hacky, but hey, it works + } else { + blockRlp = fmt.Sprintf("%#x", rlpBytes) + } + blockJSON = ethapi.RPCMarshalBlock(block, true, true, api.eth.APIBackend.ChainConfig()) + results = append(results, &BadBlockArgs{ + Hash: block.Hash(), + RLP: blockRlp, + Block: blockJSON, + }) + } + return results, nil +} + +// AccountRangeMaxResults is the maximum number of results to be returned per call +const AccountRangeMaxResults = 256 + +// AccountRange enumerates all accounts in the given block and start point in paging request +func (api *DebugAPI) AccountRange(blockNrOrHash rpc.BlockNumberOrHash, start hexutil.Bytes, maxResults int, nocode, nostorage, incompletes bool) (state.IteratorDump, error) { + var stateDb *state.StateDB + var err error + + if number, ok := blockNrOrHash.Number(); ok { + if number == rpc.PendingBlockNumber { + // 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() + if stateDb == nil { + return state.IteratorDump{}, errors.New("pending state is not available") + } + } else { + var header *types.Header + switch number { + case rpc.LatestBlockNumber: + header = api.eth.blockchain.CurrentBlock() + case rpc.FinalizedBlockNumber: + header = api.eth.blockchain.CurrentFinalBlock() + case rpc.SafeBlockNumber: + header = api.eth.blockchain.CurrentSafeBlock() + default: + block := api.eth.blockchain.GetBlockByNumber(uint64(number)) + if block == nil { + return state.IteratorDump{}, fmt.Errorf("block #%d not found", number) + } + header = block.Header() + } + if header == nil { + return state.IteratorDump{}, fmt.Errorf("block #%d not found", number) + } + stateDb, err = api.eth.BlockChain().StateAt(header.Root) + if err != nil { + return state.IteratorDump{}, err + } + } + } else if hash, ok := blockNrOrHash.Hash(); ok { + block := api.eth.blockchain.GetBlockByHash(hash) + if block == nil { + return state.IteratorDump{}, fmt.Errorf("block %s not found", hash.Hex()) + } + stateDb, err = api.eth.BlockChain().StateAt(block.Root()) + if err != nil { + return state.IteratorDump{}, err + } + } else { + return state.IteratorDump{}, errors.New("either block number or block hash must be specified") + } + + opts := &state.DumpConfig{ + SkipCode: nocode, + SkipStorage: nostorage, + OnlyWithAddresses: !incompletes, + Start: start, + Max: uint64(maxResults), + } + if maxResults > AccountRangeMaxResults || maxResults <= 0 { + opts.Max = AccountRangeMaxResults + } + return stateDb.IteratorDump(opts), nil +} + +// StorageRangeResult is the result of a debug_storageRangeAt API call. +type StorageRangeResult struct { + Storage storageMap `json:"storage"` + NextKey *common.Hash `json:"nextKey"` // nil if Storage includes the last key in the trie. +} + +type storageMap map[common.Hash]storageEntry + +type storageEntry struct { + Key *common.Hash `json:"key"` + Value common.Hash `json:"value"` +} + +// StorageRangeAt returns the storage at the given block height and transaction index. +func (api *DebugAPI) StorageRangeAt(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash, txIndex int, contractAddress common.Address, keyStart hexutil.Bytes, maxResult int) (StorageRangeResult, error) { + var block *types.Block + + block, err := api.eth.APIBackend.BlockByNumberOrHash(ctx, blockNrOrHash) + if err != nil { + return StorageRangeResult{}, err + } + if block == nil { + return StorageRangeResult{}, fmt.Errorf("block %v not found", blockNrOrHash) + } + _, _, statedb, release, err := api.eth.stateAtTransaction(ctx, block, txIndex, 0) + if err != nil { + return StorageRangeResult{}, err + } + defer release() + + return storageRangeAt(statedb, block.Root(), contractAddress, keyStart, maxResult) +} + +func storageRangeAt(statedb *state.StateDB, root common.Hash, address common.Address, start []byte, maxResult int) (StorageRangeResult, error) { + storageRoot := statedb.GetStorageRoot(address) + if storageRoot == types.EmptyRootHash || storageRoot == (common.Hash{}) { + return StorageRangeResult{}, nil // empty storage + } + id := trie.StorageTrieID(root, crypto.Keccak256Hash(address.Bytes()), storageRoot) + tr, err := trie.NewStateTrie(id, statedb.Database().TrieDB()) + if err != nil { + return StorageRangeResult{}, err + } + trieIt, err := tr.NodeIterator(start) + if err != nil { + return StorageRangeResult{}, err + } + it := trie.NewIterator(trieIt) + result := StorageRangeResult{Storage: storageMap{}} + for i := 0; i < maxResult && it.Next(); i++ { + _, content, _, err := rlp.Split(it.Value) + if err != nil { + return StorageRangeResult{}, err + } + e := storageEntry{Value: common.BytesToHash(content)} + if preimage := tr.GetKey(it.Key); preimage != nil { + preimage := common.BytesToHash(preimage) + e.Key = &preimage + } + result.Storage[common.BytesToHash(it.Key)] = e + } + // Add the 'next key' so clients can continue downloading. + if it.Next() { + next := common.BytesToHash(it.Key) + result.NextKey = &next + } + return result, nil +} + +// GetModifiedAccountsByNumber returns all accounts that have changed between the +// two blocks specified. A change is defined as a difference in nonce, balance, +// code hash, or storage hash. +// +// With one parameter, returns the list of accounts modified in the specified block. +func (api *DebugAPI) GetModifiedAccountsByNumber(startNum uint64, endNum *uint64) ([]common.Address, error) { + var startBlock, endBlock *types.Block + + startBlock = api.eth.blockchain.GetBlockByNumber(startNum) + if startBlock == nil { + return nil, fmt.Errorf("start block %x not found", startNum) + } + + if endNum == nil { + endBlock = startBlock + startBlock = api.eth.blockchain.GetBlockByHash(startBlock.ParentHash()) + if startBlock == nil { + return nil, fmt.Errorf("block %x has no parent", endBlock.Number()) + } + } else { + endBlock = api.eth.blockchain.GetBlockByNumber(*endNum) + if endBlock == nil { + return nil, fmt.Errorf("end block %d not found", *endNum) + } + } + return api.getModifiedAccounts(startBlock, endBlock) +} + +// GetModifiedAccountsByHash returns all accounts that have changed between the +// two blocks specified. A change is defined as a difference in nonce, balance, +// code hash, or storage hash. +// +// With one parameter, returns the list of accounts modified in the specified block. +func (api *DebugAPI) GetModifiedAccountsByHash(startHash common.Hash, endHash *common.Hash) ([]common.Address, error) { + var startBlock, endBlock *types.Block + startBlock = api.eth.blockchain.GetBlockByHash(startHash) + if startBlock == nil { + return nil, fmt.Errorf("start block %x not found", startHash) + } + + if endHash == nil { + endBlock = startBlock + startBlock = api.eth.blockchain.GetBlockByHash(startBlock.ParentHash()) + if startBlock == nil { + return nil, fmt.Errorf("block %x has no parent", endBlock.Number()) + } + } else { + endBlock = api.eth.blockchain.GetBlockByHash(*endHash) + if endBlock == nil { + return nil, fmt.Errorf("end block %x not found", *endHash) + } + } + return api.getModifiedAccounts(startBlock, endBlock) +} + +func (api *DebugAPI) getModifiedAccounts(startBlock, endBlock *types.Block) ([]common.Address, error) { + if startBlock.Number().Uint64() >= endBlock.Number().Uint64() { + return nil, fmt.Errorf("start block height (%d) must be less than end block height (%d)", startBlock.Number().Uint64(), endBlock.Number().Uint64()) + } + triedb := api.eth.BlockChain().TrieDB() + + oldTrie, err := trie.NewStateTrie(trie.StateTrieID(startBlock.Root()), triedb) + if err != nil { + return nil, err + } + newTrie, err := trie.NewStateTrie(trie.StateTrieID(endBlock.Root()), triedb) + if err != nil { + return nil, err + } + oldIt, err := oldTrie.NodeIterator([]byte{}) + if err != nil { + return nil, err + } + newIt, err := newTrie.NodeIterator([]byte{}) + if err != nil { + return nil, err + } + diff, _ := trie.NewDifferenceIterator(oldIt, newIt) + iter := trie.NewIterator(diff) + + var dirty []common.Address + for iter.Next() { + key := newTrie.GetKey(iter.Key) + if key == nil { + return nil, fmt.Errorf("no preimage found for hash %x", iter.Key) + } + dirty = append(dirty, common.BytesToAddress(key)) + } + return dirty, nil +} + +// GetAccessibleState returns the first number where the node has accessible +// state on disk. Note this being the post-state of that block and the pre-state +// of the next block. +// The (from, to) parameters are the sequence of blocks to search, which can go +// either forwards or backwards +func (api *DebugAPI) GetAccessibleState(from, to rpc.BlockNumber) (uint64, error) { + db := api.eth.ChainDb() + var pivot uint64 + if p := rawdb.ReadLastPivotNumber(db); p != nil { + pivot = *p + log.Info("Found fast-sync pivot marker", "number", pivot) + } + var resolveNum = func(num rpc.BlockNumber) (uint64, error) { + // We don't have state for pending (-2), so treat it as latest + if num.Int64() < 0 { + block := api.eth.blockchain.CurrentBlock() + if block == nil { + return 0, errors.New("current block missing") + } + return block.Number.Uint64(), nil + } + return uint64(num.Int64()), nil + } + var ( + start uint64 + end uint64 + delta = int64(1) + lastLog time.Time + err error + ) + if start, err = resolveNum(from); err != nil { + return 0, err + } + if end, err = resolveNum(to); err != nil { + return 0, err + } + if start == end { + return 0, errors.New("from and to needs to be different") + } + if start > end { + delta = -1 + } + for i := int64(start); i != int64(end); i += delta { + if time.Since(lastLog) > 8*time.Second { + log.Info("Finding roots", "from", start, "to", end, "at", i) + lastLog = time.Now() + } + if i < int64(pivot) { + continue + } + h := api.eth.BlockChain().GetHeaderByNumber(uint64(i)) + if h == nil { + return 0, fmt.Errorf("missing header %d", i) + } + if ok, _ := api.eth.ChainDb().Has(h.Root[:]); ok { + return uint64(i), nil + } + } + return 0, errors.New("no state found") +} + +// SetTrieFlushInterval configures how often in-memory tries are persisted +// to disk. The value is in terms of block processing time, not wall clock. +// If the value is shorter than the block generation time, or even 0 or negative, +// the node will flush trie after processing each block (effectively archive mode). +func (api *DebugAPI) SetTrieFlushInterval(interval string) error { + t, err := time.ParseDuration(interval) + if err != nil { + return err + } + api.eth.blockchain.SetTrieFlushInterval(t) + return nil +} + +// GetTrieFlushInterval gets the current value of in-memory trie flush interval +func (api *DebugAPI) GetTrieFlushInterval() string { + return api.eth.blockchain.GetTrieFlushInterval().String() +} diff --git a/eth/api_test.go b/eth/api_debug_test.go similarity index 79% rename from eth/api_test.go rename to eth/api_debug_test.go index dec1b34ddc..3d3444a871 100644 --- a/eth/api_test.go +++ b/eth/api_debug_test.go @@ -21,7 +21,6 @@ import ( "fmt" "math/big" "reflect" - "sort" "testing" "github.com/davecgh/go-spew/spew" @@ -31,6 +30,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/trie" + "golang.org/x/exp/slices" ) var dumper = spew.ConfigState{Indent: " "} @@ -58,46 +58,40 @@ func accountRangeTest(t *testing.T, trie *state.Trie, statedb *state.StateDB, st return result } -type resultHash []common.Hash - -func (h resultHash) Len() int { return len(h) } -func (h resultHash) Swap(i, j int) { h[i], h[j] = h[j], h[i] } -func (h resultHash) Less(i, j int) bool { return bytes.Compare(h[i].Bytes(), h[j].Bytes()) < 0 } - func TestAccountRange(t *testing.T) { t.Parallel() var ( - statedb = state.NewDatabaseWithConfig(rawdb.NewMemoryDatabase(), &trie.Config{Preimages: true}) - state, _ = state.New(types.EmptyRootHash, statedb, nil) - addrs = [AccountRangeMaxResults * 2]common.Address{} - m = map[common.Address]bool{} + statedb = state.NewDatabaseWithConfig(rawdb.NewMemoryDatabase(), &trie.Config{Preimages: true}) + sdb, _ = state.New(types.EmptyRootHash, statedb, nil) + addrs = [AccountRangeMaxResults * 2]common.Address{} + m = map[common.Address]bool{} ) for i := range addrs { hash := common.HexToHash(fmt.Sprintf("%x", i)) addr := common.BytesToAddress(crypto.Keccak256Hash(hash.Bytes()).Bytes()) addrs[i] = addr - state.SetBalance(addrs[i], big.NewInt(1)) + sdb.SetBalance(addrs[i], big.NewInt(1)) if _, ok := m[addr]; ok { t.Fatalf("bad") } else { m[addr] = true } } - state.Commit(true) - root := state.IntermediateRoot(true) + root, _ := sdb.Commit(0, true) + sdb, _ = state.New(root, statedb, nil) trie, err := statedb.OpenTrie(root) if err != nil { t.Fatal(err) } - accountRangeTest(t, &trie, state, common.Hash{}, AccountRangeMaxResults/2, AccountRangeMaxResults/2) + accountRangeTest(t, &trie, sdb, common.Hash{}, AccountRangeMaxResults/2, AccountRangeMaxResults/2) // test pagination - firstResult := accountRangeTest(t, &trie, state, common.Hash{}, AccountRangeMaxResults, AccountRangeMaxResults) - secondResult := accountRangeTest(t, &trie, state, common.BytesToHash(firstResult.Next), AccountRangeMaxResults, AccountRangeMaxResults) + firstResult := accountRangeTest(t, &trie, sdb, common.Hash{}, AccountRangeMaxResults, AccountRangeMaxResults) + secondResult := accountRangeTest(t, &trie, sdb, common.BytesToHash(firstResult.Next), AccountRangeMaxResults, AccountRangeMaxResults) - hList := make(resultHash, 0) + hList := make([]common.Hash, 0) for addr1 := range firstResult.Accounts { // If address is empty, then it makes no sense to compare // them as they might be two different accounts. @@ -111,9 +105,9 @@ func TestAccountRange(t *testing.T) { } // Test to see if it's possible to recover from the middle of the previous // set and get an even split between the first and second sets. - sort.Sort(hList) + slices.SortFunc(hList, common.Hash.Cmp) middleH := hList[AccountRangeMaxResults/2] - middleResult := accountRangeTest(t, &trie, state, middleH, AccountRangeMaxResults, AccountRangeMaxResults) + middleResult := accountRangeTest(t, &trie, sdb, middleH, AccountRangeMaxResults, AccountRangeMaxResults) missing, infirst, insecond := 0, 0, 0 for h := range middleResult.Accounts { if _, ok := firstResult.Accounts[h]; ok { @@ -142,8 +136,10 @@ func TestEmptyAccountRange(t *testing.T) { statedb = state.NewDatabase(rawdb.NewMemoryDatabase()) st, _ = state.New(types.EmptyRootHash, statedb, nil) ) - st.Commit(true) - st.IntermediateRoot(true) + // Commit(although nothing to flush) and re-init the statedb + st.Commit(0, true) + st, _ = state.New(types.EmptyRootHash, statedb, nil) + results := st.IteratorDump(&state.DumpConfig{ SkipCode: true, SkipStorage: true, @@ -163,9 +159,10 @@ func TestStorageRangeAt(t *testing.T) { // Create a state where account 0x010000... has a few storage entries. var ( - state, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - addr = common.Address{0x01} - keys = []common.Hash{ // hashes of Keys of storage + db = state.NewDatabaseWithConfig(rawdb.NewMemoryDatabase(), &trie.Config{Preimages: true}) + sdb, _ = state.New(types.EmptyRootHash, db, nil) + addr = common.Address{0x01} + keys = []common.Hash{ // hashes of Keys of storage common.HexToHash("340dd630ad21bf010b4e676dbfa9ba9a02175262d1fa356232cfde6cb5b47ef2"), common.HexToHash("426fcb404ab2d5d8e61a3d918108006bbb0a9be65e92235bb10eefbdb6dcd053"), common.HexToHash("48078cfed56339ea54962e72c37c7f588fc4f8e5bc173827ba75cb10a63a96a5"), @@ -179,8 +176,10 @@ func TestStorageRangeAt(t *testing.T) { } ) for _, entry := range storage { - state.SetState(addr, *entry.Key, entry.Value) + sdb.SetState(addr, *entry.Key, entry.Value) } + root, _ := sdb.Commit(0, false) + sdb, _ = state.New(root, db, nil) // Check a few combinations of limit and start/end. tests := []struct { @@ -210,11 +209,7 @@ func TestStorageRangeAt(t *testing.T) { }, } for _, test := range tests { - tr, err := state.StorageTrie(addr) - if err != nil { - t.Error(err) - } - result, err := storageRangeAt(tr, test.start, test.limit) + result, err := storageRangeAt(sdb, root, addr, test.start, test.limit) if err != nil { t.Error(err) } diff --git a/eth/api_miner.go b/eth/api_miner.go new file mode 100644 index 0000000000..477531d494 --- /dev/null +++ b/eth/api_miner.go @@ -0,0 +1,85 @@ +// 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 eth + +import ( + "math/big" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" +) + +// MinerAPI provides an API to control the miner. +type MinerAPI struct { + e *Ethereum +} + +// NewMinerAPI create a new MinerAPI instance. +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 { + return false, err + } + return true, nil +} + +// SetGasPrice sets the minimum accepted gas price for the miner. +func (api *MinerAPI) SetGasPrice(gasPrice hexutil.Big) bool { + api.e.lock.Lock() + api.e.gasPrice = (*big.Int)(&gasPrice) + api.e.lock.Unlock() + + api.e.txPool.SetGasTip((*big.Int)(&gasPrice)) + return true +} + +// SetGasLimit sets the gaslimit to target towards during mining. +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 4caab9bad6..38c0fa9743 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -35,6 +35,8 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state/pruner" "github.com/ethereum/go-ethereum/core/txpool" + "github.com/ethereum/go-ethereum/core/txpool/blobpool" + "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/eth/downloader" @@ -66,7 +68,8 @@ type Ethereum struct { config *ethconfig.Config // Handlers - txPool *txpool.TxPool + txPool *txpool.TxPool + blockchain *core.BlockChain handler *handler ethDialCandidates enode.Iterator @@ -130,8 +133,11 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { if err != nil { return nil, err } - if err := pruner.RecoverPruning(stack.ResolvePath(""), chainDb, stack.ResolvePath(config.TrieCleanCacheJournal)); err != nil { - log.Error("Failed to recover state", "error", err) + // Try to recover offline state pruning only in hash-based. + if config.StateScheme == rawdb.HashScheme { + if err := pruner.RecoverPruning(stack.ResolvePath(""), chainDb); err != nil { + log.Error("Failed to recover state", "error", err) + } } // Transfer mining-related config to the ethash config. chainConfig, err := core.LoadChainConfig(chainDb, config.Genesis) @@ -158,7 +164,6 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { p2pServer: stack.Server(), shutdownTracker: shutdowncheck.NewShutdownTracker(chainDb), } - bcVersion := rawdb.ReadDatabaseVersion(chainDb) var dbVer = "" if bcVersion != nil { @@ -182,14 +187,14 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { } cacheConfig = &core.CacheConfig{ TrieCleanLimit: config.TrieCleanCache, - TrieCleanJournal: stack.ResolvePath(config.TrieCleanCacheJournal), - TrieCleanRejournal: config.TrieCleanCacheRejournal, TrieCleanNoPrefetch: config.NoPrefetch, TrieDirtyLimit: config.TrieDirtyCache, TrieDirtyDisabled: config.NoPruning, TrieTimeLimit: config.TrieTimeout, SnapshotLimit: config.SnapshotCache, Preimages: config.Preimages, + StateHistory: config.StateHistory, + StateScheme: config.StateScheme, } ) // Override the chain config with provided settings. @@ -197,17 +202,29 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { if config.OverrideCancun != nil { overrides.OverrideCancun = config.OverrideCancun } - eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, config.Genesis, &overrides, eth.engine, vmConfig, eth.shouldPreserve, &config.TxLookupLimit) + 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) if err != nil { return nil, err } eth.bloomIndexer.Start(eth.blockchain) + if config.BlobPool.Datadir != "" { + config.BlobPool.Datadir = stack.ResolvePath(config.BlobPool.Datadir) + } + blobPool := blobpool.New(config.BlobPool, eth.blockchain) + if config.TxPool.Journal != "" { config.TxPool.Journal = stack.ResolvePath(config.TxPool.Journal) } - eth.txPool = txpool.NewTxPool(config.TxPool, eth.blockchain.Config(), eth.blockchain) + legacyPool := legacypool.New(config.TxPool, eth.blockchain) + eth.txPool, err = txpool.New(new(big.Int).SetUint64(config.TxPool.PriceLimit), eth.blockchain, []txpool.SubPool{legacyPool, blobPool}) + if err != nil { + return nil, err + } // 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{ @@ -323,7 +340,7 @@ func (s *Ethereum) Etherbase() (eb common.Address, err error) { if etherbase != (common.Address{}) { return etherbase, nil } - return common.Address{}, fmt.Errorf("etherbase must be explicitly specified") + return common.Address{}, errors.New("etherbase must be explicitly specified") } // isLocalBlock checks whether the specified block is mined @@ -399,7 +416,7 @@ func (s *Ethereum) StartMining() error { s.lock.RLock() price := s.gasPrice s.lock.RUnlock() - s.txPool.SetGasPrice(price) + s.txPool.SetGasTip(price) // Configure the local mining address eb, err := s.Etherbase() @@ -425,7 +442,7 @@ func (s *Ethereum) StartMining() error { } // If mining is started, we can disable the transaction rejection mechanism // introduced to speed sync times. - s.handler.acceptTxs.Store(true) + s.handler.enableSyncedFeatures() go s.miner.Start() } @@ -458,7 +475,7 @@ func (s *Ethereum) ChainDb() ethdb.Database { return s.chainDb } func (s *Ethereum) IsListening() bool { return true } // Always listening func (s *Ethereum) Downloader() *downloader.Downloader { return s.handler.downloader } func (s *Ethereum) Synced() bool { return s.handler.acceptTxs.Load() } -func (s *Ethereum) SetSynced() { s.handler.acceptTxs.Store(true) } +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 } @@ -512,7 +529,7 @@ func (s *Ethereum) Stop() error { // Then stop everything else. s.bloomIndexer.Close() close(s.closeBloomHandler) - s.txPool.Stop() + s.txPool.Close() s.miner.Close() s.blockchain.Stop() s.engine.Close() diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 1fe9842472..9690d43307 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -20,6 +20,7 @@ package catalyst import ( "errors" "fmt" + "math/big" "sync" "time" @@ -77,11 +78,14 @@ const ( var caps = []string{ "engine_forkchoiceUpdatedV1", "engine_forkchoiceUpdatedV2", + "engine_forkchoiceUpdatedV3", "engine_exchangeTransitionConfigurationV1", "engine_getPayloadV1", "engine_getPayloadV2", + "engine_getPayloadV3", "engine_newPayloadV1", "engine_newPayloadV2", + "engine_newPayloadV3", "engine_getPayloadBodiesByHashV1", "engine_getPayloadBodiesByRangeV1", } @@ -132,6 +136,13 @@ type ConsensusAPI struct { // NewConsensusAPI creates a new consensus api for the given backend. // The underlying blockchain needs to have a valid terminal total difficulty set. func NewConsensusAPI(eth *eth.Ethereum) *ConsensusAPI { + api := newConsensusAPIWithoutHeartbeat(eth) + go api.heartbeat() + return api +} + +// newConsensusAPIWithoutHeartbeat creates a new consensus api for the SimulatedBeacon Node. +func newConsensusAPIWithoutHeartbeat(eth *eth.Ethereum) *ConsensusAPI { if eth.BlockChain().Config().TerminalTotalDifficulty == nil { log.Warn("Engine API started but chain not configured for merge yet") } @@ -143,8 +154,6 @@ func NewConsensusAPI(eth *eth.Ethereum) *ConsensusAPI { invalidTipsets: make(map[common.Hash]*types.Header), } eth.Downloader().SetBadBlockCallback(api.setInvalidAncestor) - go api.heartbeat() - return api } @@ -165,10 +174,10 @@ func NewConsensusAPI(eth *eth.Ethereum) *ConsensusAPI { func (api *ConsensusAPI) ForkchoiceUpdatedV1(update engine.ForkchoiceStateV1, payloadAttributes *engine.PayloadAttributes) (engine.ForkChoiceResponse, error) { if payloadAttributes != nil { if payloadAttributes.Withdrawals != nil { - return engine.STATUS_INVALID, engine.InvalidParams.With(fmt.Errorf("withdrawals not supported in V1")) + return engine.STATUS_INVALID, engine.InvalidParams.With(errors.New("withdrawals not supported in V1")) } - if api.eth.BlockChain().Config().IsShanghai(payloadAttributes.Timestamp) { - return engine.STATUS_INVALID, engine.InvalidParams.With(fmt.Errorf("forkChoiceUpdateV1 called post-shanghai")) + 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) @@ -184,17 +193,36 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV2(update engine.ForkchoiceStateV1, pa return api.forkchoiceUpdated(update, payloadAttributes) } +// ForkchoiceUpdatedV3 is equivalent to V2 with the addition of parent beacon block root in the payload attributes. +func (api *ConsensusAPI) ForkchoiceUpdatedV3(update engine.ForkchoiceStateV1, payloadAttributes *engine.PayloadAttributes) (engine.ForkChoiceResponse, error) { + if payloadAttributes != nil { + if err := api.verifyPayloadAttributes(payloadAttributes); err != nil { + return engine.STATUS_INVALID, engine.InvalidParams.With(err) + } + } + return api.forkchoiceUpdated(update, payloadAttributes) +} + func (api *ConsensusAPI) verifyPayloadAttributes(attr *engine.PayloadAttributes) error { - if !api.eth.BlockChain().Config().IsShanghai(attr.Timestamp) { - // Reject payload attributes with withdrawals before shanghai - if attr.Withdrawals != nil { - return errors.New("withdrawals before shanghai") - } - } else { - // Reject payload attributes with nil withdrawals after shanghai - if attr.Withdrawals == nil { - return errors.New("missing withdrawals list") - } + c := api.eth.BlockChain().Config() + + // Verify withdrawals attribute for Shanghai. + if err := checkAttribute(c.IsShanghai, attr.Withdrawals != nil, attr.Timestamp); err != nil { + return fmt.Errorf("invalid withdrawals: %w", err) + } + // Verify beacon root attribute for Cancun. + if err := checkAttribute(c.IsCancun, attr.BeaconRoot != nil, attr.Timestamp); err != nil { + return fmt.Errorf("invalid parent beacon block root: %w", err) + } + return nil +} + +func checkAttribute(active func(*big.Int, uint64) bool, exists bool, time uint64) error { + if active(common.Big0, time) && !exists { + return errors.New("fork active, missing expected attribute") + } + if !active(common.Big0, time) && exists { + return errors.New("fork inactive, unexpected attribute set") } return nil } @@ -342,6 +370,7 @@ func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payl FeeRecipient: payloadAttributes.SuggestedFeeRecipient, Random: payloadAttributes.Random, Withdrawals: payloadAttributes.Withdrawals, + BeaconRoot: payloadAttributes.BeaconRoot, } id := args.Id() // If we already are busy generating this work, then we do not need @@ -385,14 +414,14 @@ func (api *ConsensusAPI) ExchangeTransitionConfigurationV1(config engine.Transit TerminalBlockNumber: config.TerminalBlockNumber, }, nil } - return nil, fmt.Errorf("invalid terminal block hash") + return nil, errors.New("invalid terminal block hash") } return &engine.TransitionConfigurationV1{TerminalTotalDifficulty: (*hexutil.Big)(ttd)}, nil } // GetPayloadV1 returns a cached payload by id. func (api *ConsensusAPI) GetPayloadV1(payloadID engine.PayloadID) (*engine.ExecutableData, error) { - data, err := api.getPayload(payloadID) + data, err := api.getPayload(payloadID, false) if err != nil { return nil, err } @@ -401,12 +430,17 @@ func (api *ConsensusAPI) GetPayloadV1(payloadID engine.PayloadID) (*engine.Execu // GetPayloadV2 returns a cached payload by id. func (api *ConsensusAPI) GetPayloadV2(payloadID engine.PayloadID) (*engine.ExecutionPayloadEnvelope, error) { - return api.getPayload(payloadID) + return api.getPayload(payloadID, false) } -func (api *ConsensusAPI) getPayload(payloadID engine.PayloadID) (*engine.ExecutionPayloadEnvelope, error) { +// GetPayloadV3 returns a cached payload by id. +func (api *ConsensusAPI) GetPayloadV3(payloadID engine.PayloadID) (*engine.ExecutionPayloadEnvelope, error) { + 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) + data := api.localBlocks.get(payloadID, full) if data == nil { return nil, engine.UnknownPayload } @@ -416,24 +450,49 @@ func (api *ConsensusAPI) getPayload(payloadID engine.PayloadID) (*engine.Executi // NewPayloadV1 creates an Eth1 block, inserts it in the chain, and returns the status of the chain. func (api *ConsensusAPI) NewPayloadV1(params engine.ExecutableData) (engine.PayloadStatusV1, error) { if params.Withdrawals != nil { - return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(fmt.Errorf("withdrawals not supported in V1")) + return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("withdrawals not supported in V1")) } - return api.newPayload(params) + return api.newPayload(params, nil, nil) } // NewPayloadV2 creates an Eth1 block, inserts it in the chain, and returns the status of the chain. func (api *ConsensusAPI) NewPayloadV2(params engine.ExecutableData) (engine.PayloadStatusV1, error) { - if api.eth.BlockChain().Config().IsShanghai(params.Timestamp) { + if api.eth.BlockChain().Config().IsShanghai(new(big.Int).SetUint64(params.Number), params.Timestamp) { if params.Withdrawals == nil { - return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(fmt.Errorf("nil withdrawals post-shanghai")) + 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(fmt.Errorf("non-nil withdrawals pre-shanghai")) + return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("non-nil withdrawals pre-shanghai")) } - return api.newPayload(params) + if api.eth.BlockChain().Config().IsCancun(new(big.Int).SetUint64(params.Number), params.Timestamp) { + return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("newPayloadV2 called post-cancun")) + } + return api.newPayload(params, nil, nil) } -func (api *ConsensusAPI) newPayload(params engine.ExecutableData) (engine.PayloadStatusV1, error) { +// NewPayloadV3 creates an Eth1 block, inserts it in the chain, and returns the status of the chain. +func (api *ConsensusAPI) NewPayloadV3(params engine.ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash) (engine.PayloadStatusV1, error) { + 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 params.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 parentBeaconBlockRoot post-cancun")) + } + + if !api.eth.BlockChain().Config().IsCancun(new(big.Int).SetUint64(params.Number), params.Timestamp) { + return engine.PayloadStatusV1{Status: engine.INVALID}, engine.UnsupportedFork.With(errors.New("newPayloadV3 called pre-cancun")) + } + + 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: // // 1. NewPayload( execdata-N ) is invoked from the CL. It goes all the way down to @@ -451,9 +510,9 @@ func (api *ConsensusAPI) newPayload(params engine.ExecutableData) (engine.Payloa defer api.newPayloadLock.Unlock() log.Trace("Engine API request received", "method", "NewPayload", "number", params.Number, "hash", params.BlockHash) - block, err := engine.ExecutableDataToBlock(params) + block, err := engine.ExecutableDataToBlock(params, versionedHashes, beaconRoot) if err != nil { - log.Debug("Invalid NewPayload params", "params", params, "error", err) + log.Warn("Invalid NewPayload params", "params", params, "error", err) return engine.PayloadStatusV1{Status: engine.INVALID}, nil } // Stash away the last update to warn the user if the beacon client goes offline @@ -714,7 +773,7 @@ func (api *ConsensusAPI) ExchangeCapabilities([]string) []string { return caps } -// GetPayloadBodiesV1 implements engine_getPayloadBodiesByHashV1 which allows for retrieval of a list +// 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 { var bodies = make([]*engine.ExecutionPayloadBodyV1, len(hashes)) diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index 5bab7ba186..59f44fafea 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -37,15 +37,18 @@ import ( "github.com/ethereum/go-ethereum/core" "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/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/params" "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/trie" + "github.com/mattn/go-colorable" ) var ( @@ -67,8 +70,11 @@ func generateMergeChain(n int, merged bool) (*core.Genesis, []*types.Block) { engine = beaconConsensus.NewFaker() } genesis := &core.Genesis{ - Config: &config, - Alloc: core.GenesisAlloc{testAddr: {Balance: testBalance}}, + Config: &config, + Alloc: core.GenesisAlloc{ + testAddr: {Balance: testBalance}, + params.BeaconRootsStorageAddress: {Balance: common.Big0, Code: common.Hex2Bytes("3373fffffffffffffffffffffffffffffffffffffffe14604457602036146024575f5ffd5b620180005f350680545f35146037575f5ffd5b6201800001545f5260205ff35b6201800042064281555f359062018000015500")}, + }, ExtraData: []byte("test genesis"), Timestamp: 9000, BaseFee: big.NewInt(params.InitialBaseFee), @@ -106,7 +112,7 @@ func TestEth2AssembleBlock(t *testing.T) { if err != nil { t.Fatalf("error signing transaction, err=%v", err) } - ethservice.TxPool().AddLocal(tx) + ethservice.TxPool().Add([]*types.Transaction{tx}, true, false) blockParams := engine.PayloadAttributes{ Timestamp: blocks[9].Time() + 5, } @@ -142,7 +148,8 @@ func TestEth2AssembleBlockWithAnotherBlocksTxs(t *testing.T) { api := NewConsensusAPI(ethservice) // Put the 10th block's tx in the pool and produce a new block - api.eth.TxPool().AddRemotesSync(blocks[9].Transactions()) + txs := blocks[9].Transactions() + api.eth.TxPool().Add(txs, false, true) blockParams := engine.PayloadAttributes{ Timestamp: blocks[8].Time() + 5, } @@ -181,7 +188,8 @@ func TestEth2PrepareAndGetPayload(t *testing.T) { api := NewConsensusAPI(ethservice) // Put the 10th block's tx in the pool and produce a new block - ethservice.TxPool().AddLocals(blocks[9].Transactions()) + txs := blocks[9].Transactions() + ethservice.TxPool().Add(txs, true, false) blockParams := engine.PayloadAttributes{ Timestamp: blocks[8].Time() + 5, } @@ -201,6 +209,7 @@ func TestEth2PrepareAndGetPayload(t *testing.T) { Timestamp: blockParams.Timestamp, FeeRecipient: blockParams.SuggestedFeeRecipient, Random: blockParams.Random, + BeaconRoot: blockParams.BeaconRoot, }).Id() execData, err := api.GetPayloadV1(payloadID) if err != nil { @@ -303,7 +312,7 @@ 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().AddLocal(tx) + ethservice.TxPool().Add([]*types.Transaction{tx}, true, false) execData, err := assembleWithTransactions(api, parent.Hash(), &engine.PayloadAttributes{ Timestamp: parent.Time() + 5, @@ -311,7 +320,7 @@ func TestEth2NewBlock(t *testing.T) { if err != nil { t.Fatalf("Failed to create the executable data %v", err) } - block, err := engine.ExecutableDataToBlock(*execData) + block, err := engine.ExecutableDataToBlock(*execData, nil, nil) if err != nil { t.Fatalf("Failed to convert executable data to block %v", err) } @@ -353,7 +362,7 @@ func TestEth2NewBlock(t *testing.T) { if err != nil { t.Fatalf("Failed to create the executable data %v", err) } - block, err := engine.ExecutableDataToBlock(*execData) + block, err := engine.ExecutableDataToBlock(*execData, nil, nil) if err != nil { t.Fatalf("Failed to convert executable data to block %v", err) } @@ -472,7 +481,7 @@ func TestFullAPI(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().AddLocal(tx) + ethservice.TxPool().Add([]*types.Transaction{tx}, true, false) } setupBlocks(t, ethservice, 10, parent, callback, nil) @@ -598,7 +607,7 @@ func TestNewPayloadOnInvalidChain(t *testing.T) { GasPrice: big.NewInt(2 * params.InitialBaseFee), Data: logCode, }) - ethservice.TxPool().AddRemotesSync([]*types.Transaction{tx}) + ethservice.TxPool().Add([]*types.Transaction{tx}, false, true) var ( params = engine.PayloadAttributes{ Timestamp: parent.Time + 1, @@ -664,6 +673,7 @@ func assembleBlock(api *ConsensusAPI, parentHash common.Hash, params *engine.Pay FeeRecipient: params.SuggestedFeeRecipient, Random: params.Random, Withdrawals: params.Withdrawals, + BeaconRoot: params.BeaconRoot, } payload, err := api.eth.Miner().BuildPayload(args) if err != nil { @@ -985,7 +995,7 @@ func TestSimultaneousNewBlock(t *testing.T) { t.Fatal(testErr) } } - block, err := engine.ExecutableDataToBlock(*execData) + block, err := engine.ExecutableDataToBlock(*execData, nil, nil) if err != nil { t.Fatalf("Failed to convert executable data to block %v", err) } @@ -1065,6 +1075,7 @@ func TestWithdrawals(t *testing.T) { FeeRecipient: blockParams.SuggestedFeeRecipient, Random: blockParams.Random, Withdrawals: blockParams.Withdrawals, + BeaconRoot: blockParams.BeaconRoot, }).Id() execData, err := api.GetPayloadV2(payloadID) if err != nil { @@ -1112,6 +1123,7 @@ func TestWithdrawals(t *testing.T) { FeeRecipient: blockParams.SuggestedFeeRecipient, Random: blockParams.Random, Withdrawals: blockParams.Withdrawals, + BeaconRoot: blockParams.BeaconRoot, }).Id() execData, err = api.GetPayloadV2(payloadID) if err != nil { @@ -1242,6 +1254,7 @@ func TestNilWithdrawals(t *testing.T) { Timestamp: test.blockParams.Timestamp, FeeRecipient: test.blockParams.SuggestedFeeRecipient, Random: test.blockParams.Random, + BeaconRoot: test.blockParams.BeaconRoot, }).Id() execData, err := api.GetPayloadV2(payloadID) if err != nil { @@ -1272,7 +1285,7 @@ func setupBodies(t *testing.T) (*node.Node, *eth.Ethereum, []*types.Block) { 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().AddLocal(tx) + ethservice.TxPool().Add([]*types.Transaction{tx}, false, false) } withdrawals := make([][]*types.Withdrawal, 10) @@ -1508,3 +1521,124 @@ func equalBody(a *types.Body, b *engine.ExecutionPayloadBodyV1) bool { } return reflect.DeepEqual(a.Withdrawals, b.Withdrawals) } + +func TestBlockToPayloadWithBlobs(t *testing.T) { + header := types.Header{} + var txs []*types.Transaction + + inner := types.BlobTx{ + BlobHashes: make([]common.Hash, 1), + } + + txs = append(txs, types.NewTx(&inner)) + sidecars := []*types.BlobTxSidecar{ + { + Blobs: make([]kzg4844.Blob, 1), + Commitments: make([]kzg4844.Commitment, 1), + Proofs: make([]kzg4844.Proof, 1), + }, + } + + block := types.NewBlock(&header, txs, nil, nil, trie.NewStackTrie(nil)) + envelope := engine.BlockToExecutableData(block, nil, sidecars) + var want int + for _, tx := range txs { + want += len(tx.BlobHashes()) + } + if got := len(envelope.BlobsBundle.Commitments); got != want { + t.Fatalf("invalid number of commitments: got %v, want %v", got, want) + } + if got := len(envelope.BlobsBundle.Proofs); got != want { + t.Fatalf("invalid number of proofs: got %v, want %v", got, want) + } + if got := len(envelope.BlobsBundle.Blobs); got != want { + t.Fatalf("invalid number of blobs: got %v, want %v", got, want) + } + _, err := engine.ExecutableDataToBlock(*envelope.ExecutionPayload, make([]common.Hash, 1), nil) + if err != nil { + t.Error(err) + } +} + +// This checks that beaconRoot is applied to the state from the engine API. +func TestParentBeaconBlockRoot(t *testing.T) { + log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(true)))) + + genesis, blocks := generateMergeChain(10, true) + + // Set cancun time to last block + 5 seconds + time := blocks[len(blocks)-1].Time() + 5 + genesis.Config.ShanghaiTime = &time + genesis.Config.CancunTime = &time + + n, ethservice := startEthService(t, genesis, blocks) + ethservice.Merger().ReachTTD() + defer n.Close() + + api := NewConsensusAPI(ethservice) + + // 11: Build Shanghai block with no withdrawals. + parent := ethservice.BlockChain().CurrentHeader() + blockParams := engine.PayloadAttributes{ + Timestamp: parent.Time + 5, + Withdrawals: make([]*types.Withdrawal, 0), + BeaconRoot: &common.Hash{42}, + } + fcState := engine.ForkchoiceStateV1{ + HeadBlockHash: parent.Hash(), + } + resp, err := api.ForkchoiceUpdatedV2(fcState, &blockParams) + if err != nil { + t.Fatalf("error preparing payload, err=%v", err.(*engine.EngineAPIError).ErrorData()) + } + if resp.PayloadStatus.Status != engine.VALID { + t.Fatalf("unexpected status (got: %s, want: %s)", resp.PayloadStatus.Status, engine.VALID) + } + + // 11: verify state root is the same as parent + payloadID := (&miner.BuildPayloadArgs{ + Parent: fcState.HeadBlockHash, + Timestamp: blockParams.Timestamp, + FeeRecipient: blockParams.SuggestedFeeRecipient, + Random: blockParams.Random, + Withdrawals: blockParams.Withdrawals, + BeaconRoot: blockParams.BeaconRoot, + }).Id() + execData, err := api.GetPayloadV3(payloadID) + if err != nil { + t.Fatalf("error getting payload, err=%v", err) + } + + // 11: verify locally built block + if status, err := api.NewPayloadV3(*execData.ExecutionPayload, []common.Hash{}, &common.Hash{42}); err != nil { + t.Fatalf("error validating payload: %v", err) + } else if status.Status != engine.VALID { + t.Fatalf("invalid payload") + } + + fcState.HeadBlockHash = execData.ExecutionPayload.BlockHash + resp, err = api.ForkchoiceUpdatedV3(fcState, nil) + if err != nil { + t.Fatalf("error preparing payload, err=%v", err.(*engine.EngineAPIError).ErrorData()) + } + if resp.PayloadStatus.Status != engine.VALID { + t.Fatalf("unexpected status (got: %s, want: %s)", resp.PayloadStatus.Status, engine.VALID) + } + + // 11: verify beacon root was processed. + db, _, err := ethservice.APIBackend.StateAndHeaderByNumber(context.Background(), rpc.BlockNumber(execData.ExecutionPayload.Number)) + if err != nil { + t.Fatalf("unable to load db: %v", err) + } + var ( + timeIdx = common.BigToHash(big.NewInt(int64(execData.ExecutionPayload.Timestamp % 98304))) + rootIdx = common.BigToHash(big.NewInt(int64((execData.ExecutionPayload.Timestamp % 98304) + 98304))) + ) + + if num := db.GetState(params.BeaconRootsStorageAddress, timeIdx); num != timeIdx { + t.Fatalf("incorrect number stored: want %s, got %s", timeIdx, num) + } + if root := db.GetState(params.BeaconRootsStorageAddress, rootIdx); root != *blockParams.BeaconRoot { + t.Fatalf("incorrect root stored: want %s, got %s", *blockParams.BeaconRoot, root) + } +} diff --git a/eth/catalyst/queue.go b/eth/catalyst/queue.go index e8037aacad..634dc1b2e6 100644 --- a/eth/catalyst/queue.go +++ b/eth/catalyst/queue.go @@ -73,7 +73,7 @@ func (q *payloadQueue) put(id engine.PayloadID, payload *miner.Payload) { } // get retrieves a previously stored payload item or nil if it does not exist. -func (q *payloadQueue) get(id engine.PayloadID) *engine.ExecutionPayloadEnvelope { +func (q *payloadQueue) get(id engine.PayloadID, full bool) *engine.ExecutionPayloadEnvelope { q.lock.RLock() defer q.lock.RUnlock() @@ -82,7 +82,10 @@ func (q *payloadQueue) get(id engine.PayloadID) *engine.ExecutionPayloadEnvelope return nil // no more items } if item.id == id { - return item.payload.Resolve() + if !full { + return item.payload.Resolve() + } + return item.payload.ResolveFull() } } return nil diff --git a/eth/catalyst/simulated_beacon.go b/eth/catalyst/simulated_beacon.go new file mode 100644 index 0000000000..1f7a3266cd --- /dev/null +++ b/eth/catalyst/simulated_beacon.go @@ -0,0 +1,276 @@ +// 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 catalyst + +import ( + "crypto/rand" + "errors" + "sync" + "time" + + "github.com/ethereum/go-ethereum/beacon/engine" + "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" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/node" + "github.com/ethereum/go-ethereum/rpc" +) + +const devEpochLength = 32 + +// withdrawalQueue implements a FIFO queue which holds withdrawals that are +// pending inclusion. +type withdrawalQueue struct { + pending chan *types.Withdrawal +} + +// 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") + } + 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 { + break + } + default: + return withdrawals + } + } +} + +type SimulatedBeacon struct { + shutdownCh chan struct{} + eth *eth.Ethereum + period uint64 + withdrawals withdrawalQueue + + feeRecipient common.Address + feeRecipientLock sync.Mutex // lock gates concurrent access to the feeRecipient + + engineAPI *ConsensusAPI + curForkchoiceState engine.ForkchoiceStateV1 + lastBlockTime uint64 +} + +func NewSimulatedBeacon(period uint64, eth *eth.Ethereum) (*SimulatedBeacon, error) { + chainConfig := eth.APIBackend.ChainConfig() + if !chainConfig.IsDevMode { + return nil, errors.New("incompatible pre-existing chain configuration") + } + block := eth.BlockChain().CurrentBlock() + current := engine.ForkchoiceStateV1{ + HeadBlockHash: block.Hash(), + SafeBlockHash: block.Hash(), + FinalizedBlockHash: block.Hash(), + } + engineAPI := newConsensusAPIWithoutHeartbeat(eth) + + // if genesis block, send forkchoiceUpdated to trigger transition to PoS + if block.Number.Sign() == 0 { + if _, err := engineAPI.ForkchoiceUpdatedV2(current, nil); err != nil { + return nil, err + } + } + return &SimulatedBeacon{ + eth: eth, + period: period, + shutdownCh: make(chan struct{}), + engineAPI: engineAPI, + lastBlockTime: block.Time, + curForkchoiceState: current, + withdrawals: withdrawalQueue{make(chan *types.Withdrawal, 20)}, + }, nil +} + +func (c *SimulatedBeacon) setFeeRecipient(feeRecipient common.Address) { + c.feeRecipientLock.Lock() + c.feeRecipient = feeRecipient + c.feeRecipientLock.Unlock() +} + +// Start invokes the SimulatedBeacon life-cycle function in a goroutine. +func (c *SimulatedBeacon) Start() error { + if c.period == 0 { + go c.loopOnDemand() + } else { + go c.loop() + } + return nil +} + +// Stop halts the SimulatedBeacon service. +func (c *SimulatedBeacon) Stop() error { + close(c.shutdownCh) + return nil +} + +// sealBlock initiates payload building for a new block and creates a new block +// with the completed payload. +func (c *SimulatedBeacon) sealBlock(withdrawals []*types.Withdrawal) error { + tstamp := uint64(time.Now().Unix()) + if tstamp <= c.lastBlockTime { + tstamp = c.lastBlockTime + 1 + } + c.feeRecipientLock.Lock() + feeRecipient := c.feeRecipient + c.feeRecipientLock.Unlock() + + // Reset to CurrentBlock in case of the chain was rewound + if header := c.eth.BlockChain().CurrentBlock(); c.curForkchoiceState.HeadBlockHash != header.Hash() { + finalizedHash := c.finalizedBlockHash(header.Number.Uint64()) + c.setCurrentState(header.Hash(), *finalizedHash) + } + + var random [32]byte + rand.Read(random[:]) + fcResponse, err := c.engineAPI.ForkchoiceUpdatedV2(c.curForkchoiceState, &engine.PayloadAttributes{ + Timestamp: tstamp, + SuggestedFeeRecipient: feeRecipient, + Withdrawals: withdrawals, + Random: random, + }) + 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 + } + payload := envelope.ExecutionPayload + + var finalizedHash common.Hash + if payload.Number%devEpochLength == 0 { + finalizedHash = payload.BlockHash + } else { + if fh := c.finalizedBlockHash(payload.Number); fh == nil { + return errors.New("chain rewind interrupted calculation of finalized block hash") + } else { + finalizedHash = *fh + } + } + + // Mark the payload as canon + if _, err = c.engineAPI.NewPayloadV2(*payload); err != nil { + return err + } + c.setCurrentState(payload.BlockHash, finalizedHash) + // Mark the block containing the payload as canonical + if _, err = c.engineAPI.ForkchoiceUpdatedV2(c.curForkchoiceState, nil); err != nil { + return err + } + c.lastBlockTime = payload.Timestamp + return nil +} + +// loopOnDemand runs the block production loop for "on-demand" configuration (period = 0) +func (c *SimulatedBeacon) loopOnDemand() { + var ( + newTxs = make(chan core.NewTxsEvent) + sub = c.eth.TxPool().SubscribeNewTxsEvent(newTxs) + ) + defer sub.Unsubscribe() + + for { + select { + case <-c.shutdownCh: + return + case w := <-c.withdrawals.pending: + withdrawals := append(c.withdrawals.gatherPending(9), w) + if err := c.sealBlock(withdrawals); err != nil { + log.Warn("Error performing sealing work", "err", err) + } + case <-newTxs: + withdrawals := c.withdrawals.gatherPending(10) + if err := c.sealBlock(withdrawals); err != nil { + log.Warn("Error performing sealing work", "err", err) + } + } + } +} + +// loop runs the block production loop for non-zero period configuration +func (c *SimulatedBeacon) loop() { + timer := time.NewTimer(0) + for { + select { + case <-c.shutdownCh: + return + case <-timer.C: + withdrawals := c.withdrawals.gatherPending(10) + if err := c.sealBlock(withdrawals); err != nil { + log.Warn("Error performing sealing work", "err", err) + } else { + timer.Reset(time.Second * time.Duration(c.period)) + } + } + } +} + +// finalizedBlockHash returns the block hash of the finalized block corresponding to the given number +// or nil if doesn't exist in the chain. +func (c *SimulatedBeacon) finalizedBlockHash(number uint64) *common.Hash { + var finalizedNumber uint64 + if number%devEpochLength == 0 { + finalizedNumber = number + } else { + finalizedNumber = (number - 1) / devEpochLength * devEpochLength + } + + if finalizedBlock := c.eth.BlockChain().GetBlockByNumber(finalizedNumber); finalizedBlock != nil { + fh := finalizedBlock.Hash() + return &fh + } + return nil +} + +// setCurrentState sets the current forkchoice state +func (c *SimulatedBeacon) setCurrentState(headHash, finalizedHash common.Hash) { + c.curForkchoiceState = engine.ForkchoiceStateV1{ + HeadBlockHash: headHash, + SafeBlockHash: headHash, + FinalizedBlockHash: finalizedHash, + } +} + +func RegisterSimulatedBeaconAPIs(stack *node.Node, sim *SimulatedBeacon) { + stack.RegisterAPIs([]rpc.API{ + { + Namespace: "dev", + Service: &api{sim}, + Version: "1.0", + }, + }) +} diff --git a/internal/debug/trace_fallback.go b/eth/catalyst/simulated_beacon_api.go similarity index 61% rename from internal/debug/trace_fallback.go rename to eth/catalyst/simulated_beacon_api.go index ec07d991ef..93670257f6 100644 --- a/internal/debug/trace_fallback.go +++ b/eth/catalyst/simulated_beacon_api.go @@ -1,4 +1,4 @@ -// Copyright 2016 The go-ethereum Authors +// 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 @@ -14,19 +14,23 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -//go:build !go1.5 -// +build !go1.5 +package catalyst -// no-op implementation of tracing methods for Go < 1.5. +import ( + "context" -package debug + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) -import "errors" - -func (*HandlerT) StartGoTrace(string) error { - return errors.New("tracing is not supported on Go < 1.5") +type api struct { + simBeacon *SimulatedBeacon } -func (*HandlerT) StopGoTrace() error { - return errors.New("tracing is not supported on Go < 1.5") +func (a *api) AddWithdrawal(ctx context.Context, withdrawal *types.Withdrawal) error { + return a.simBeacon.withdrawals.add(withdrawal) +} + +func (a *api) SetFeeRecipient(ctx context.Context, feeRecipient common.Address) { + a.simBeacon.setFeeRecipient(feeRecipient) } diff --git a/eth/catalyst/simulated_beacon_test.go b/eth/catalyst/simulated_beacon_test.go new file mode 100644 index 0000000000..0df195fb9d --- /dev/null +++ b/eth/catalyst/simulated_beacon_test.go @@ -0,0 +1,141 @@ +// 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 catalyst + +import ( + "context" + "math/big" + "testing" + "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/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/node" + "github.com/ethereum/go-ethereum/p2p" + "github.com/ethereum/go-ethereum/params" +) + +func startSimulatedBeaconEthService(t *testing.T, genesis *core.Genesis) (*node.Node, *eth.Ethereum, *SimulatedBeacon) { + t.Helper() + + n, err := node.New(&node.Config{ + P2P: p2p.Config{ + ListenAddr: "127.0.0.1:8545", + NoDiscovery: true, + MaxPeers: 0, + }, + }) + if err != nil { + t.Fatal("can't create node:", err) + } + + ethcfg := ðconfig.Config{Genesis: genesis, SyncMode: downloader.FullSync, TrieTimeout: time.Minute, TrieDirtyCache: 256, TrieCleanCache: 256} + ethservice, err := eth.New(n, ethcfg) + if err != nil { + t.Fatal("can't create eth service:", err) + } + + simBeacon, err := NewSimulatedBeacon(1, ethservice) + if err != nil { + t.Fatal("can't create simulated beacon:", err) + } + + n.RegisterLifecycle(simBeacon) + + if err := n.Start(); err != nil { + t.Fatal("can't start node:", err) + } + + ethservice.SetSynced() + return n, ethservice, simBeacon +} + +// send 20 transactions, >10 withdrawals and ensure they are included in order +// send enough transactions to fill multiple blocks +func TestSimulatedBeaconSendWithdrawals(t *testing.T) { + var withdrawals []types.Withdrawal + txs := make(map[common.Hash]types.Transaction) + + var ( + // testKey is a private key to use for funding a tester account. + testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + + // testAddr is the Ethereum address of the tester account. + testAddr = crypto.PubkeyToAddress(testKey.PublicKey) + ) + + // short period (1 second) for testing purposes + var gasLimit uint64 = 10_000_000 + genesis := core.DeveloperGenesisBlock(gasLimit, testAddr) + node, ethService, mock := startSimulatedBeaconEthService(t, genesis) + _ = mock + defer node.Close() + + chainHeadCh := make(chan core.ChainHeadEvent, 10) + subscription := ethService.BlockChain().SubscribeChainHeadEvent(chainHeadCh) + defer subscription.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 + signer := types.NewEIP155Signer(ethService.BlockChain().Config().ChainID) + for i := 0; i < 20; i++ { + tx, err := types.SignTx(types.NewTransaction(uint64(i), common.Address{}, big.NewInt(1000), params.TxGas, big.NewInt(params.InitialBaseFee), nil), signer, testKey) + if err != nil { + t.Fatalf("error signing transaction, err=%v", err) + } + txs[tx.Hash()] = *tx + + if err := ethService.APIBackend.SendTx(context.Background(), tx); err != nil { + t.Fatal("SendTx failed", err) + } + } + + includedTxs := make(map[common.Hash]struct{}) + var includedWithdrawals []uint64 + + timer := time.NewTimer(12 * time.Second) + for { + select { + case evt := <-chainHeadCh: + for _, includedTx := range evt.Block.Transactions() { + includedTxs[includedTx.Hash()] = struct{}{} + } + for _, includedWithdrawal := range evt.Block.Withdrawals() { + includedWithdrawals = append(includedWithdrawals, includedWithdrawal.Index) + } + + // ensure all withdrawals/txs included. this will take two blocks b/c number of withdrawals > 10 + if len(includedTxs) == len(txs) && len(includedWithdrawals) == len(withdrawals) && evt.Block.Number().Cmp(big.NewInt(2)) == 0 { + return + } + case <-timer.C: + t.Fatal("timed out without including all withdrawals/txs") + } + } +} diff --git a/eth/catalyst/tester.go b/eth/catalyst/tester.go index c4eafd30d9..3e9159a175 100644 --- a/eth/catalyst/tester.go +++ b/eth/catalyst/tester.go @@ -42,7 +42,7 @@ type FullSyncTester struct { // stack for launching and stopping the service controlled by node. func RegisterFullSyncTester(stack *node.Node, backend *eth.Ethereum, block *types.Block) (*FullSyncTester, error) { cl := &FullSyncTester{ - api: NewConsensusAPI(backend), + api: newConsensusAPIWithoutHeartbeat(backend), block: block, closed: make(chan struct{}), } @@ -75,7 +75,7 @@ func (tester *FullSyncTester) Start() error { } // Trigger beacon sync with the provided block header as // trusted chain head. - err := tester.api.eth.Downloader().BeaconSync(downloader.FullSync, tester.block.Header(), nil) + err := tester.api.eth.Downloader().BeaconSync(downloader.FullSync, tester.block.Header(), tester.block.Header()) if err != nil { log.Info("Failed to beacon sync", "err", err) } diff --git a/eth/downloader/queue.go b/eth/downloader/queue.go index e9907297a0..e557158797 100644 --- a/eth/downloader/queue.go +++ b/eth/downloader/queue.go @@ -31,6 +31,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" + "github.com/ethereum/go-ethereum/params" ) const ( @@ -796,6 +797,37 @@ func (q *queue) DeliverBodies(id string, txLists [][]*types.Transaction, txListH return errInvalidBody } } + // Blocks must have a number of blobs corresponding to the header gas usage, + // and zero before the Cancun hardfork. + var blobs int + for _, tx := range txLists[index] { + // Count the number of blobs to validate against the header's blobGasUsed + blobs += len(tx.BlobHashes()) + + // Validate the data blobs individually too + if tx.Type() == types.BlobTxType { + if len(tx.BlobHashes()) == 0 { + return errInvalidBody + } + for _, hash := range tx.BlobHashes() { + if hash[0] != params.BlobTxHashVersion { + return errInvalidBody + } + } + if tx.BlobTxSidecar() != nil { + return errInvalidBody + } + } + } + if header.BlobGasUsed != nil { + if want := *header.BlobGasUsed / params.BlobTxBlobGasPerBlob; uint64(blobs) != want { // div because the header is surely good vs the body might be bloated + return errInvalidBody + } + } else { + if blobs != 0 { + return errInvalidBody + } + } return nil } diff --git a/eth/downloader/skeleton.go b/eth/downloader/skeleton.go index 12eb5700f8..59df82bd9e 100644 --- a/eth/downloader/skeleton.go +++ b/eth/downloader/skeleton.go @@ -367,13 +367,31 @@ func (s *skeleton) sync(head *types.Header) (*types.Header, error) { s.filler.resume() } defer func() { - if filled := s.filler.suspend(); filled != nil { - // If something was filled, try to delete stale sync helpers. If - // unsuccessful, warn the user, but not much else we can do (it's - // a programming error, just let users report an issue and don't - // choke in the meantime). - if err := s.cleanStales(filled); err != nil { - log.Error("Failed to clean stale beacon headers", "err", err) + // The filler needs to be suspended, but since it can block for a while + // when there are many blocks queued up for full-sync importing, run it + // on a separate goroutine and consume head messages that need instant + // replies. + done := make(chan struct{}) + go func() { + defer close(done) + if filled := s.filler.suspend(); filled != nil { + // If something was filled, try to delete stale sync helpers. If + // unsuccessful, warn the user, but not much else we can do (it's + // a programming error, just let users report an issue and don't + // choke in the meantime). + if err := s.cleanStales(filled); err != nil { + log.Error("Failed to clean stale beacon headers", "err", err) + } + } + }() + // Wait for the suspend to finish, consuming head events in the meantime + // and dropping them on the floor. + for { + select { + case <-done: + return + case event := <-s.headEvents: + event.errc <- errors.New("beacon syncer reorging") } } }() @@ -630,7 +648,7 @@ func (s *skeleton) processNewHead(head *types.Header, final *types.Header, force } if parent := rawdb.ReadSkeletonHeader(s.db, number-1); parent.Hash() != head.ParentHash { if force { - log.Warn("Beacon chain forked", "ancestor", parent.Number, "hash", parent.Hash(), "want", head.ParentHash) + log.Warn("Beacon chain forked", "ancestor", number-1, "hash", parent.Hash(), "want", head.ParentHash) } return true } diff --git a/eth/downloader/testchain_test.go b/eth/downloader/testchain_test.go index d791723b05..1bf03411d1 100644 --- a/eth/downloader/testchain_test.go +++ b/eth/downloader/testchain_test.go @@ -30,6 +30,7 @@ import ( "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/trie" ) // Test chain parameters. @@ -43,7 +44,7 @@ var ( Alloc: core.GenesisAlloc{testAddress: {Balance: big.NewInt(1000000000000000)}}, BaseFee: big.NewInt(params.InitialBaseFee), } - testGenesis = testGspec.MustCommit(testDB) + testGenesis = testGspec.MustCommit(testDB, trie.NewDatabase(testDB, trie.HashDefaults)) ) // The common prefix of all test chains: diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index a98d9ee4aa..55441a2cb9 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -27,7 +27,9 @@ import ( "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/txpool" + "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/eth/downloader" "github.com/ethereum/go-ethereum/eth/gasprice" "github.com/ethereum/go-ethereum/ethdb" @@ -57,25 +59,26 @@ var LightClientGPO = gasprice.Config{ // Defaults contains default settings for use on the Ethereum main net. var Defaults = Config{ - SyncMode: downloader.SnapSync, - NetworkId: 1, - TxLookupLimit: 2350000, - LightPeers: 100, - UltraLightFraction: 75, - DatabaseCache: 512, - TrieCleanCache: 154, - TrieCleanCacheJournal: "triecache", - TrieCleanCacheRejournal: 60 * time.Minute, - TrieDirtyCache: 256, - TrieTimeout: 60 * time.Minute, - SnapshotCache: 102, - FilterLogCacheSize: 32, - Miner: miner.DefaultConfig, - TxPool: txpool.DefaultConfig, - RPCGasCap: 50000000, - RPCEVMTimeout: 5 * time.Second, - GPO: FullNodeGPO, - RPCTxFeeCap: 1, // 1 ether + SyncMode: downloader.SnapSync, + NetworkId: 1, + TxLookupLimit: 2350000, + TransactionHistory: 2350000, + StateHistory: params.FullImmutabilityThreshold, + StateScheme: rawdb.HashScheme, + LightPeers: 100, + DatabaseCache: 512, + TrieCleanCache: 154, + TrieDirtyCache: 256, + TrieTimeout: 60 * time.Minute, + SnapshotCache: 102, + FilterLogCacheSize: 32, + Miner: miner.DefaultConfig, + TxPool: legacypool.DefaultConfig, + BlobPool: blobpool.DefaultConfig, + RPCGasCap: 50000000, + RPCEVMTimeout: 5 * time.Second, + GPO: FullNodeGPO, + RPCTxFeeCap: 1, // 1 ether } //go:generate go run github.com/fjl/gencodec -type Config -formats toml -out gen_config.go @@ -98,7 +101,11 @@ type Config struct { NoPruning bool // Whether to disable pruning and flush everything to disk NoPrefetch bool // Whether to disable prefetching and only load state on demand - 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. + StateScheme string `toml:",omitempty"` // State scheme used to store ethereum state and merkle trie nodes on top // RequiredBlocks is a set of block number -> hash mappings which must be in the // canonical chain of all remote peers. Setting the option makes geth verify the @@ -113,24 +120,17 @@ type Config struct { LightNoPrune bool `toml:",omitempty"` // Whether to disable light chain pruning LightNoSyncServe bool `toml:",omitempty"` // Whether to serve light clients before syncing - // Ultra Light client options - UltraLightServers []string `toml:",omitempty"` // List of trusted ultra light servers - UltraLightFraction int `toml:",omitempty"` // Percentage of trusted servers to accept an announcement - UltraLightOnlyAnnounce bool `toml:",omitempty"` // Whether to only announce headers, or also serve them - // Database options SkipBcVersionCheck bool `toml:"-"` DatabaseHandles int `toml:"-"` DatabaseCache int DatabaseFreezer string - TrieCleanCache int - TrieCleanCacheJournal string `toml:",omitempty"` // Disk journal directory for trie cache to survive node restarts - TrieCleanCacheRejournal time.Duration `toml:",omitempty"` // Time interval to regenerate the journal for clean cache - TrieDirtyCache int - TrieTimeout time.Duration - SnapshotCache int - Preimages bool + TrieCleanCache int + TrieDirtyCache int + TrieTimeout time.Duration + SnapshotCache int + Preimages bool // This is the number of blocks for which logs will be cached in the filter system. FilterLogCacheSize int @@ -139,7 +139,8 @@ type Config struct { Miner miner.Config // Transaction pool options - TxPool txpool.Config + TxPool legacypool.Config + BlobPool blobpool.Config // Gas Price Oracle options GPO gasprice.Config @@ -162,6 +163,9 @@ type Config struct { // OverrideCancun (TODO: remove after the fork) OverrideCancun *uint64 `toml:",omitempty"` + + // OverrideVerkle (TODO: remove after the fork) + OverrideVerkle *uint64 `toml:",omitempty"` } // CreateConsensusEngine creates a consensus engine for the given chain config. diff --git a/eth/ethconfig/gen_config.go b/eth/ethconfig/gen_config.go index 0e2f037740..2abddc9e0d 100644 --- a/eth/ethconfig/gen_config.go +++ b/eth/ethconfig/gen_config.go @@ -7,7 +7,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/txpool" + "github.com/ethereum/go-ethereum/core/txpool/blobpool" + "github.com/ethereum/go-ethereum/core/txpool/legacypool" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/gasprice" "github.com/ethereum/go-ethereum/miner" @@ -24,6 +25,9 @@ func (c Config) MarshalTOML() (interface{}, error) { NoPruning bool NoPrefetch bool TxLookupLimit uint64 `toml:",omitempty"` + TransactionHistory uint64 `toml:",omitempty"` + StateHistory uint64 `toml:",omitempty"` + StateScheme string `toml:",omitempty"` RequiredBlocks map[uint64]common.Hash `toml:"-"` LightServ int `toml:",omitempty"` LightIngress int `toml:",omitempty"` @@ -31,23 +35,19 @@ func (c Config) MarshalTOML() (interface{}, error) { LightPeers int `toml:",omitempty"` LightNoPrune bool `toml:",omitempty"` LightNoSyncServe bool `toml:",omitempty"` - UltraLightServers []string `toml:",omitempty"` - UltraLightFraction int `toml:",omitempty"` - UltraLightOnlyAnnounce bool `toml:",omitempty"` SkipBcVersionCheck bool `toml:"-"` DatabaseHandles int `toml:"-"` DatabaseCache int DatabaseFreezer string TrieCleanCache int - TrieCleanCacheJournal string `toml:",omitempty"` - TrieCleanCacheRejournal time.Duration `toml:",omitempty"` TrieDirtyCache int TrieTimeout time.Duration SnapshotCache int Preimages bool FilterLogCacheSize int Miner miner.Config - TxPool txpool.Config + TxPool legacypool.Config + BlobPool blobpool.Config GPO gasprice.Config EnablePreimageRecording bool DocRoot string `toml:"-"` @@ -55,6 +55,7 @@ func (c Config) MarshalTOML() (interface{}, error) { RPCEVMTimeout time.Duration RPCTxFeeCap float64 OverrideCancun *uint64 `toml:",omitempty"` + OverrideVerkle *uint64 `toml:",omitempty"` } var enc Config enc.Genesis = c.Genesis @@ -65,6 +66,9 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.NoPruning = c.NoPruning enc.NoPrefetch = c.NoPrefetch enc.TxLookupLimit = c.TxLookupLimit + enc.TransactionHistory = c.TransactionHistory + enc.StateHistory = c.StateHistory + enc.StateScheme = c.StateScheme enc.RequiredBlocks = c.RequiredBlocks enc.LightServ = c.LightServ enc.LightIngress = c.LightIngress @@ -72,16 +76,11 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.LightPeers = c.LightPeers enc.LightNoPrune = c.LightNoPrune enc.LightNoSyncServe = c.LightNoSyncServe - enc.UltraLightServers = c.UltraLightServers - enc.UltraLightFraction = c.UltraLightFraction - enc.UltraLightOnlyAnnounce = c.UltraLightOnlyAnnounce enc.SkipBcVersionCheck = c.SkipBcVersionCheck enc.DatabaseHandles = c.DatabaseHandles enc.DatabaseCache = c.DatabaseCache enc.DatabaseFreezer = c.DatabaseFreezer enc.TrieCleanCache = c.TrieCleanCache - enc.TrieCleanCacheJournal = c.TrieCleanCacheJournal - enc.TrieCleanCacheRejournal = c.TrieCleanCacheRejournal enc.TrieDirtyCache = c.TrieDirtyCache enc.TrieTimeout = c.TrieTimeout enc.SnapshotCache = c.SnapshotCache @@ -89,6 +88,7 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.FilterLogCacheSize = c.FilterLogCacheSize enc.Miner = c.Miner enc.TxPool = c.TxPool + enc.BlobPool = c.BlobPool enc.GPO = c.GPO enc.EnablePreimageRecording = c.EnablePreimageRecording enc.DocRoot = c.DocRoot @@ -96,6 +96,7 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.RPCEVMTimeout = c.RPCEVMTimeout enc.RPCTxFeeCap = c.RPCTxFeeCap enc.OverrideCancun = c.OverrideCancun + enc.OverrideVerkle = c.OverrideVerkle return &enc, nil } @@ -110,6 +111,9 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { NoPruning *bool NoPrefetch *bool TxLookupLimit *uint64 `toml:",omitempty"` + TransactionHistory *uint64 `toml:",omitempty"` + StateHistory *uint64 `toml:",omitempty"` + StateScheme *string `toml:",omitempty"` RequiredBlocks map[uint64]common.Hash `toml:"-"` LightServ *int `toml:",omitempty"` LightIngress *int `toml:",omitempty"` @@ -117,23 +121,19 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { LightPeers *int `toml:",omitempty"` LightNoPrune *bool `toml:",omitempty"` LightNoSyncServe *bool `toml:",omitempty"` - UltraLightServers []string `toml:",omitempty"` - UltraLightFraction *int `toml:",omitempty"` - UltraLightOnlyAnnounce *bool `toml:",omitempty"` SkipBcVersionCheck *bool `toml:"-"` DatabaseHandles *int `toml:"-"` DatabaseCache *int DatabaseFreezer *string TrieCleanCache *int - TrieCleanCacheJournal *string `toml:",omitempty"` - TrieCleanCacheRejournal *time.Duration `toml:",omitempty"` TrieDirtyCache *int TrieTimeout *time.Duration SnapshotCache *int Preimages *bool FilterLogCacheSize *int Miner *miner.Config - TxPool *txpool.Config + TxPool *legacypool.Config + BlobPool *blobpool.Config GPO *gasprice.Config EnablePreimageRecording *bool DocRoot *string `toml:"-"` @@ -141,6 +141,7 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { RPCEVMTimeout *time.Duration RPCTxFeeCap *float64 OverrideCancun *uint64 `toml:",omitempty"` + OverrideVerkle *uint64 `toml:",omitempty"` } var dec Config if err := unmarshal(&dec); err != nil { @@ -170,6 +171,15 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.TxLookupLimit != nil { c.TxLookupLimit = *dec.TxLookupLimit } + if dec.TransactionHistory != nil { + c.TransactionHistory = *dec.TransactionHistory + } + if dec.StateHistory != nil { + c.StateHistory = *dec.StateHistory + } + if dec.StateScheme != nil { + c.StateScheme = *dec.StateScheme + } if dec.RequiredBlocks != nil { c.RequiredBlocks = dec.RequiredBlocks } @@ -191,15 +201,6 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.LightNoSyncServe != nil { c.LightNoSyncServe = *dec.LightNoSyncServe } - if dec.UltraLightServers != nil { - c.UltraLightServers = dec.UltraLightServers - } - if dec.UltraLightFraction != nil { - c.UltraLightFraction = *dec.UltraLightFraction - } - if dec.UltraLightOnlyAnnounce != nil { - c.UltraLightOnlyAnnounce = *dec.UltraLightOnlyAnnounce - } if dec.SkipBcVersionCheck != nil { c.SkipBcVersionCheck = *dec.SkipBcVersionCheck } @@ -215,12 +216,6 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.TrieCleanCache != nil { c.TrieCleanCache = *dec.TrieCleanCache } - if dec.TrieCleanCacheJournal != nil { - c.TrieCleanCacheJournal = *dec.TrieCleanCacheJournal - } - if dec.TrieCleanCacheRejournal != nil { - c.TrieCleanCacheRejournal = *dec.TrieCleanCacheRejournal - } if dec.TrieDirtyCache != nil { c.TrieDirtyCache = *dec.TrieDirtyCache } @@ -242,6 +237,9 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.TxPool != nil { c.TxPool = *dec.TxPool } + if dec.BlobPool != nil { + c.BlobPool = *dec.BlobPool + } if dec.GPO != nil { c.GPO = *dec.GPO } @@ -263,5 +261,8 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.OverrideCancun != nil { c.OverrideCancun = dec.OverrideCancun } + if dec.OverrideVerkle != nil { + c.OverrideVerkle = dec.OverrideVerkle + } return nil } diff --git a/eth/fetcher/block_fetcher_test.go b/eth/fetcher/block_fetcher_test.go index 6d8516fa6a..7c490df3f7 100644 --- a/eth/fetcher/block_fetcher_test.go +++ b/eth/fetcher/block_fetcher_test.go @@ -44,7 +44,7 @@ var ( Alloc: core.GenesisAlloc{testAddress: {Balance: big.NewInt(1000000000000000)}}, BaseFee: big.NewInt(params.InitialBaseFee), } - genesis = gspec.MustCommit(testdb) + genesis = gspec.MustCommit(testdb, trie.NewDatabase(testdb, trie.HashDefaults)) unknownBlock = types.NewBlock(&types.Header{Root: types.EmptyRootHash, GasLimit: params.GenesisGasLimit, BaseFee: big.NewInt(params.InitialBaseFee)}, nil, nil, nil, trie.NewStackTrie(nil)) ) diff --git a/eth/fetcher/tx_fetcher.go b/eth/fetcher/tx_fetcher.go index 39727e0079..95fef0cdee 100644 --- a/eth/fetcher/tx_fetcher.go +++ b/eth/fetcher/tx_fetcher.go @@ -294,6 +294,7 @@ func (f *TxFetcher) Enqueue(peer string, txs []*types.Transaction, direct bool) otherreject int64 ) batch := txs[i:end] + for j, err := range f.addTxs(batch) { // Track the transaction hash if the price is too low for us. // Avoid re-request this transaction when we receive another diff --git a/eth/filters/api.go b/eth/filters/api.go index f9ae70eba7..cc08b442e8 100644 --- a/eth/filters/api.go +++ b/eth/filters/api.go @@ -33,6 +33,11 @@ import ( "github.com/ethereum/go-ethereum/rpc" ) +var ( + errInvalidTopic = errors.New("invalid topic(s)") + errFilterNotFound = errors.New("filter not found") +) + // filter is a helper struct that holds meta information over the filter type // and associated subscription in the event system. type filter struct { @@ -376,7 +381,7 @@ func (api *FilterAPI) GetFilterLogs(ctx context.Context, id rpc.ID) ([]*types.Lo api.filtersMu.Unlock() if !found || f.typ != LogsSubscription { - return nil, fmt.Errorf("filter not found") + return nil, errFilterNotFound } var filter *Filter @@ -452,7 +457,7 @@ func (api *FilterAPI) GetFilterChanges(id rpc.ID) (interface{}, error) { } } - return []interface{}{}, fmt.Errorf("filter not found") + return []interface{}{}, errFilterNotFound } // returnHashes is a helper that will return an empty hash array case the given hash array is nil, @@ -491,7 +496,7 @@ func (args *FilterCriteria) UnmarshalJSON(data []byte) error { if raw.BlockHash != nil { if raw.FromBlock != nil || raw.ToBlock != nil { // BlockHash is mutually exclusive with FromBlock/ToBlock criteria - return fmt.Errorf("cannot specify both BlockHash and FromBlock/ToBlock, choose one or the other") + return errors.New("cannot specify both BlockHash and FromBlock/ToBlock, choose one or the other") } args.BlockHash = raw.BlockHash } else { @@ -564,11 +569,11 @@ func (args *FilterCriteria) UnmarshalJSON(data []byte) error { } args.Topics[i] = append(args.Topics[i], parsed) } else { - return fmt.Errorf("invalid topic(s)") + return errInvalidTopic } } default: - return fmt.Errorf("invalid topic(s)") + return errInvalidTopic } } } diff --git a/eth/filters/api_test.go b/eth/filters/api_test.go index 0a80d0f8dd..822bc826f6 100644 --- a/eth/filters/api_test.go +++ b/eth/filters/api_test.go @@ -56,7 +56,7 @@ func TestUnmarshalJSONNewFilterArgs(t *testing.T) { // from, to block number var test1 FilterCriteria - vector := fmt.Sprintf(`{"fromBlock":"%#x","toBlock":"%#x"}`, fromBlock, toBlock) + vector := fmt.Sprintf(`{"fromBlock":"%v","toBlock":"%v"}`, fromBlock, toBlock) if err := json.Unmarshal([]byte(vector), &test1); err != nil { t.Fatal(err) } diff --git a/eth/filters/filter.go b/eth/filters/filter.go index 8ba482817e..a5750c1934 100644 --- a/eth/filters/filter.go +++ b/eth/filters/filter.go @@ -106,32 +106,32 @@ func (f *Filter) Logs(ctx context.Context) ([]*types.Log, error) { } return f.blockLogs(ctx, header) } - // Short-cut if all we care about is pending logs - if f.begin == rpc.PendingBlockNumber.Int64() { - if f.end != rpc.PendingBlockNumber.Int64() { - return nil, errors.New("invalid block range") - } - return f.pendingLogs() - } - // Figure out the limits of the filter range - header, _ := f.sys.backend.HeaderByNumber(ctx, rpc.LatestBlockNumber) - if header == nil { - return nil, nil - } + var ( - err error - head = header.Number.Int64() - pending = f.end == rpc.PendingBlockNumber.Int64() + beginPending = f.begin == rpc.PendingBlockNumber.Int64() + endPending = f.end == rpc.PendingBlockNumber.Int64() ) + + // special case for pending logs + if beginPending && !endPending { + return nil, errors.New("invalid block range") + } + + // Short-cut if all we care about is pending logs + if beginPending && endPending { + return f.pendingLogs(), nil + } + resolveSpecial := func(number int64) (int64, error) { var hdr *types.Header switch number { - case rpc.LatestBlockNumber.Int64(): - return head, nil - case rpc.PendingBlockNumber.Int64(): + case rpc.LatestBlockNumber.Int64(), rpc.PendingBlockNumber.Int64(): // we should return head here since we've already captured // that we need to get the pending logs in the pending boolean above - return head, nil + hdr, _ = f.sys.backend.HeaderByNumber(ctx, rpc.LatestBlockNumber) + if hdr == nil { + return 0, errors.New("latest header not found") + } case rpc.FinalizedBlockNumber.Int64(): hdr, _ = f.sys.backend.HeaderByNumber(ctx, rpc.FinalizedBlockNumber) if hdr == nil { @@ -147,57 +147,92 @@ func (f *Filter) Logs(ctx context.Context) ([]*types.Log, error) { } return hdr.Number.Int64(), nil } + + var err error + // range query need to resolve the special begin/end block number if f.begin, err = resolveSpecial(f.begin); err != nil { return nil, err } if f.end, err = resolveSpecial(f.end); err != nil { return nil, err } - // Gather all indexed logs, and finish with non indexed ones + + logChan, errChan := f.rangeLogsAsync(ctx) + var logs []*types.Log + for { + select { + 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 + } + } +} + +// rangeLogsAsync retrieves block-range logs that match the filter criteria asynchronously, +// it creates and returns two channels: one for delivering log data, and one for reporting errors. +func (f *Filter) rangeLogsAsync(ctx context.Context) (chan *types.Log, chan error) { var ( - logs []*types.Log - end = uint64(f.end) - size, sections = f.sys.backend.BloomStatus() + logChan = make(chan *types.Log) + errChan = make(chan error) ) - if indexed := sections * size; indexed > uint64(f.begin) { - if indexed > end { - logs, err = f.indexedLogs(ctx, end) - } else { - logs, err = f.indexedLogs(ctx, indexed-1) + + go func() { + defer func() { + close(errChan) + close(logChan) + }() + + // Gather all indexed logs, and finish with non indexed ones + var ( + end = uint64(f.end) + size, sections = f.sys.backend.BloomStatus() + err error + ) + if indexed := sections * size; indexed > uint64(f.begin) { + if indexed > end { + indexed = end + 1 + } + if err = f.indexedLogs(ctx, indexed-1, logChan); err != nil { + errChan <- err + return + } } - if err != nil { - return logs, err + + if err := f.unindexedLogs(ctx, end, logChan); err != nil { + errChan <- err + return } - } - rest, err := f.unindexedLogs(ctx, end) - logs = append(logs, rest...) - if pending { - pendingLogs, err := f.pendingLogs() - if err != nil { - return nil, err - } - logs = append(logs, pendingLogs...) - } - return logs, err + + errChan <- nil + }() + + return logChan, errChan } // indexedLogs returns the logs matching the filter criteria based on the bloom // bits indexed available locally or via the network. -func (f *Filter) indexedLogs(ctx context.Context, end uint64) ([]*types.Log, error) { +func (f *Filter) indexedLogs(ctx context.Context, end uint64, logChan chan *types.Log) error { // Create a matcher session and request servicing from the backend matches := make(chan uint64, 64) session, err := f.matcher.Start(ctx, uint64(f.begin), end, matches) if err != nil { - return nil, err + return err } defer session.Close() f.sys.backend.ServiceFilter(ctx, session) - // Iterate over the matches until exhausted or context closed - var logs []*types.Log - for { select { case number, ok := <-matches: @@ -207,47 +242,50 @@ func (f *Filter) indexedLogs(ctx context.Context, end uint64) ([]*types.Log, err if err == nil { f.begin = int64(end) + 1 } - return logs, err + return err } f.begin = int64(number) + 1 // Retrieve the suggested block and pull any truly matching logs header, err := f.sys.backend.HeaderByNumber(ctx, rpc.BlockNumber(number)) if header == nil || err != nil { - return logs, err + return err } found, err := f.checkMatches(ctx, header) if err != nil { - return logs, err + return err + } + for _, log := range found { + logChan <- log } - logs = append(logs, found...) case <-ctx.Done(): - return logs, ctx.Err() + return ctx.Err() } } } // unindexedLogs returns the logs matching the filter criteria based on raw block // iteration and bloom matching. -func (f *Filter) unindexedLogs(ctx context.Context, end uint64) ([]*types.Log, error) { - var logs []*types.Log - +func (f *Filter) unindexedLogs(ctx context.Context, end uint64, logChan chan *types.Log) error { for ; f.begin <= int64(end); f.begin++ { - if f.begin%10 == 0 && ctx.Err() != nil { - return logs, ctx.Err() - } header, err := f.sys.backend.HeaderByNumber(ctx, rpc.BlockNumber(f.begin)) if header == nil || err != nil { - return logs, err + return err } found, err := f.blockLogs(ctx, header) if err != nil { - return logs, err + return err + } + for _, log := range found { + select { + case logChan <- log: + case <-ctx.Done(): + return ctx.Err() + } } - logs = append(logs, found...) } - return logs, nil + return nil } // blockLogs returns the logs matching the filter criteria within a single block. @@ -294,60 +332,62 @@ 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, error) { +func (f *Filter) pendingLogs() []*types.Log { block, receipts := f.sys.backend.PendingBlockAndReceipts() + 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), nil + return filterLogs(unfiltered, nil, nil, f.addresses, f.topics) } - return nil, nil + return nil } -func includes(addresses []common.Address, a common.Address) bool { - for _, addr := range addresses { - if addr == a { +// 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 ret []*types.Log -Logs: - for _, log := range logs { + var check = func(log *types.Log) bool { if fromBlock != nil && fromBlock.Int64() >= 0 && fromBlock.Uint64() > log.BlockNumber { - continue + return false } if toBlock != nil && toBlock.Int64() >= 0 && toBlock.Uint64() < log.BlockNumber { - continue + return false } - if len(addresses) > 0 && !includes(addresses, log.Address) { - continue + return false } // If the to filtered topics is greater than the amount of topics in logs, skip. if len(topics) > len(log.Topics) { - continue + return false } for i, sub := range topics { - match := len(sub) == 0 // empty rule set == wildcard - for _, topic := range sub { - if log.Topics[i] == topic { - match = true - break - } + if len(sub) == 0 { + continue // empty rule set == wildcard } - if !match { - continue Logs + if !includes(sub, log.Topics[i]) { + return false } } - ret = append(ret, log) + return true + } + var ret []*types.Log + for _, log := range logs { + if check(log) { + ret = append(ret, log) + } } return ret } diff --git a/eth/filters/filter_system.go b/eth/filters/filter_system.go index 9fc20f335b..35e396c23e 100644 --- a/eth/filters/filter_system.go +++ b/eth/filters/filter_system.go @@ -20,6 +20,7 @@ package filters import ( "context" + "errors" "fmt" "sync" "sync/atomic" @@ -331,7 +332,7 @@ func (es *EventSystem) SubscribeLogs(crit ethereum.FilterQuery, logs chan []*typ if from >= 0 && to == rpc.LatestBlockNumber { return es.subscribeLogs(crit, logs), nil } - return nil, fmt.Errorf("invalid from and to block combination: from > to") + return nil, errors.New("invalid from and to block combination: from > to") } // subscribeMinedPendingLogs creates a subscription that returned mined and @@ -443,15 +444,6 @@ func (es *EventSystem) handlePendingLogs(filters filterIndex, ev []*types.Log) { } } -func (es *EventSystem) handleRemovedLogs(filters filterIndex, ev core.RemovedLogsEvent) { - for _, f := range filters[LogsSubscription] { - matchedLogs := filterLogs(ev.Logs, f.logsCrit.FromBlock, 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 @@ -572,7 +564,7 @@ func (es *EventSystem) eventLoop() { case ev := <-es.logsCh: es.handleLogs(index, ev) case ev := <-es.rmLogsCh: - es.handleRemovedLogs(index, ev) + es.handleLogs(index, ev.Logs) case ev := <-es.pendingLogsCh: es.handlePendingLogs(index, ev) case ev := <-es.chainCh: diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go index ae0c83eb29..b5d716ae59 100644 --- a/eth/filters/filter_system_test.go +++ b/eth/filters/filter_system_test.go @@ -50,6 +50,8 @@ type testBackend struct { rmLogsFeed event.Feed pendingLogsFeed event.Feed chainFeed event.Feed + pendingBlock *types.Block + pendingReceipts types.Receipts } func (b *testBackend) ChainConfig() *params.ChainConfig { @@ -119,12 +121,12 @@ func (b *testBackend) GetReceipts(ctx context.Context, hash common.Hash) (types. } func (b *testBackend) GetLogs(ctx context.Context, hash common.Hash, number uint64) ([][]*types.Log, error) { - logs := rawdb.ReadLogs(b.db, hash, number, params.TestChainConfig) + logs := rawdb.ReadLogs(b.db, hash, number) return logs, nil } func (b *testBackend) PendingBlockAndReceipts() (*types.Block, types.Receipts) { - return nil, nil + return b.pendingBlock, b.pendingReceipts } func (b *testBackend) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription { diff --git a/eth/filters/filter_test.go b/eth/filters/filter_test.go index d10e0f1d94..a076fb7377 100644 --- a/eth/filters/filter_test.go +++ b/eth/filters/filter_test.go @@ -18,17 +18,23 @@ package filters import ( "context" + "encoding/json" "math/big" - "reflect" + "strings" "testing" + "time" + "github.com/ethereum/go-ethereum/accounts/abi" "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/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rpc" + "github.com/ethereum/go-ethereum/trie" ) func makeReceipt(addr common.Address) *types.Receipt { @@ -80,7 +86,7 @@ func BenchmarkFilters(b *testing.B) { // The test txs are not properly signed, can't simply create a chain // and then import blocks. TODO(rjl493456442) try to get rid of the // manual database writes. - gspec.MustCommit(db) + gspec.MustCommit(db, trie.NewDatabase(db, trie.HashDefaults)) for i, block := range chain { rawdb.WriteBlock(db, block) @@ -102,140 +108,264 @@ func BenchmarkFilters(b *testing.B) { func TestFilters(t *testing.T) { var ( - db, _ = rawdb.NewLevelDBDatabase(t.TempDir(), 0, 0, "", false) - _, sys = newTestFilterSystem(t, db, Config{}) + db = rawdb.NewMemoryDatabase() + _, sys = newTestFilterSystem(t, db, Config{}) + // Sender account key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") addr = crypto.PubkeyToAddress(key1.PublicKey) + signer = types.NewLondonSigner(big.NewInt(1)) + // Logging contract + contract = common.Address{0xfe} + contract2 = common.Address{0xff} + abiStr = `[{"inputs":[],"name":"log0","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"t1","type":"uint256"}],"name":"log1","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"t1","type":"uint256"},{"internalType":"uint256","name":"t2","type":"uint256"}],"name":"log2","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"t1","type":"uint256"},{"internalType":"uint256","name":"t2","type":"uint256"},{"internalType":"uint256","name":"t3","type":"uint256"}],"name":"log3","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"t1","type":"uint256"},{"internalType":"uint256","name":"t2","type":"uint256"},{"internalType":"uint256","name":"t3","type":"uint256"},{"internalType":"uint256","name":"t4","type":"uint256"}],"name":"log4","outputs":[],"stateMutability":"nonpayable","type":"function"}]` + /* + // SPDX-License-Identifier: GPL-3.0 + pragma solidity >=0.7.0 <0.9.0; + + contract Logger { + function log0() external { + assembly { + log0(0, 0) + } + } + + function log1(uint t1) external { + assembly { + log1(0, 0, t1) + } + } + + function log2(uint t1, uint t2) external { + assembly { + log2(0, 0, t1, t2) + } + } + + function log3(uint t1, uint t2, uint t3) external { + assembly { + log3(0, 0, t1, t2, t3) + } + } + + function log4(uint t1, uint t2, uint t3, uint t4) external { + assembly { + log4(0, 0, t1, t2, t3, t4) + } + } + } + */ + bytecode = common.FromHex("608060405234801561001057600080fd5b50600436106100575760003560e01c80630aa731851461005c5780632a4c08961461006657806378b9a1f314610082578063c670f8641461009e578063c683d6a3146100ba575b600080fd5b6100646100d6565b005b610080600480360381019061007b9190610143565b6100dc565b005b61009c60048036038101906100979190610196565b6100e8565b005b6100b860048036038101906100b391906101d6565b6100f2565b005b6100d460048036038101906100cf9190610203565b6100fa565b005b600080a0565b808284600080a3505050565b8082600080a25050565b80600080a150565b80828486600080a450505050565b600080fd5b6000819050919050565b6101208161010d565b811461012b57600080fd5b50565b60008135905061013d81610117565b92915050565b60008060006060848603121561015c5761015b610108565b5b600061016a8682870161012e565b935050602061017b8682870161012e565b925050604061018c8682870161012e565b9150509250925092565b600080604083850312156101ad576101ac610108565b5b60006101bb8582860161012e565b92505060206101cc8582860161012e565b9150509250929050565b6000602082840312156101ec576101eb610108565b5b60006101fa8482850161012e565b91505092915050565b6000806000806080858703121561021d5761021c610108565b5b600061022b8782880161012e565b945050602061023c8782880161012e565b935050604061024d8782880161012e565b925050606061025e8782880161012e565b9150509295919450925056fea264697066735822122073a4b156f487e59970dc1ef449cc0d51467268f676033a17188edafcee861f9864736f6c63430008110033") hash1 = common.BytesToHash([]byte("topic1")) hash2 = common.BytesToHash([]byte("topic2")) hash3 = common.BytesToHash([]byte("topic3")) hash4 = common.BytesToHash([]byte("topic4")) + hash5 = common.BytesToHash([]byte("topic5")) gspec = &core.Genesis{ - Config: params.TestChainConfig, - Alloc: core.GenesisAlloc{addr: {Balance: big.NewInt(1000000)}}, + Config: params.TestChainConfig, + Alloc: core.GenesisAlloc{ + addr: {Balance: big.NewInt(0).Mul(big.NewInt(100), big.NewInt(params.Ether))}, + contract: {Balance: big.NewInt(0), Code: bytecode}, + contract2: {Balance: big.NewInt(0), Code: bytecode}, + }, BaseFee: big.NewInt(params.InitialBaseFee), } ) - defer db.Close() - _, chain, receipts := core.GenerateChainWithGenesis(gspec, ethash.NewFaker(), 1000, func(i int, gen *core.BlockGen) { + contractABI, err := abi.JSON(strings.NewReader(abiStr)) + if err != nil { + t.Fatal(err) + } + + // Hack: GenerateChainWithGenesis creates a new db. + // Commit the genesis manually and use GenerateChain. + _, err = gspec.Commit(db, trie.NewDatabase(db, nil)) + if err != nil { + t.Fatal(err) + } + chain, _ := core.GenerateChain(gspec.Config, gspec.ToBlock(), ethash.NewFaker(), db, 1000, func(i int, gen *core.BlockGen) { switch i { case 1: - receipt := types.NewReceipt(nil, false, 0) - receipt.Logs = []*types.Log{ - { - Address: addr, - Topics: []common.Hash{hash1}, - }, + data, err := contractABI.Pack("log1", hash1.Big()) + if err != nil { + t.Fatal(err) } - gen.AddUncheckedReceipt(receipt) - gen.AddUncheckedTx(types.NewTransaction(1, common.HexToAddress("0x1"), big.NewInt(1), 1, gen.BaseFee(), nil)) + tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{ + Nonce: 0, + GasPrice: gen.BaseFee(), + Gas: 30000, + To: &contract, + Data: data, + }), signer, key1) + gen.AddTx(tx) + tx2, _ := types.SignTx(types.NewTx(&types.LegacyTx{ + Nonce: 1, + GasPrice: gen.BaseFee(), + Gas: 30000, + To: &contract2, + Data: data, + }), signer, key1) + gen.AddTx(tx2) case 2: - receipt := types.NewReceipt(nil, false, 0) - receipt.Logs = []*types.Log{ - { - Address: addr, - Topics: []common.Hash{hash2}, - }, + data, err := contractABI.Pack("log2", hash2.Big(), hash1.Big()) + if err != nil { + t.Fatal(err) } - gen.AddUncheckedReceipt(receipt) - gen.AddUncheckedTx(types.NewTransaction(2, common.HexToAddress("0x2"), big.NewInt(2), 2, gen.BaseFee(), nil)) - + tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{ + Nonce: 2, + GasPrice: gen.BaseFee(), + Gas: 30000, + To: &contract, + Data: data, + }), signer, key1) + gen.AddTx(tx) case 998: - receipt := types.NewReceipt(nil, false, 0) - receipt.Logs = []*types.Log{ - { - Address: addr, - Topics: []common.Hash{hash3}, - }, + data, err := contractABI.Pack("log1", hash3.Big()) + if err != nil { + t.Fatal(err) } - gen.AddUncheckedReceipt(receipt) - gen.AddUncheckedTx(types.NewTransaction(998, common.HexToAddress("0x998"), big.NewInt(998), 998, gen.BaseFee(), nil)) + tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{ + Nonce: 3, + GasPrice: gen.BaseFee(), + Gas: 30000, + To: &contract2, + Data: data, + }), signer, key1) + gen.AddTx(tx) case 999: - receipt := types.NewReceipt(nil, false, 0) - receipt.Logs = []*types.Log{ - { - Address: addr, - Topics: []common.Hash{hash4}, - }, + data, err := contractABI.Pack("log1", hash4.Big()) + if err != nil { + t.Fatal(err) } - gen.AddUncheckedReceipt(receipt) - gen.AddUncheckedTx(types.NewTransaction(999, common.HexToAddress("0x999"), big.NewInt(999), 999, gen.BaseFee(), nil)) + tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{ + Nonce: 4, + GasPrice: gen.BaseFee(), + Gas: 30000, + To: &contract, + Data: data, + }), signer, key1) + gen.AddTx(tx) } }) - // The test txs are not properly signed, can't simply create a chain - // and then import blocks. TODO(rjl493456442) try to get rid of the - // manual database writes. - gspec.MustCommit(db) - for i, block := range chain { - rawdb.WriteBlock(db, block) - rawdb.WriteCanonicalHash(db, block.Hash(), block.NumberU64()) - rawdb.WriteHeadBlockHash(db, block.Hash()) - rawdb.WriteReceipts(db, block.Hash(), block.NumberU64(), receipts[i]) + var l uint64 + bc, err := core.NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, &l) + if err != nil { + t.Fatal(err) + } + _, err = bc.InsertChain(chain) + if err != nil { + t.Fatal(err) } // Set block 998 as Finalized (-3) - rawdb.WriteFinalizedBlockHash(db, chain[998].Hash()) + bc.SetFinalized(chain[998].Header()) - filter := sys.NewRangeFilter(0, -1, []common.Address{addr}, [][]common.Hash{{hash1, hash2, hash3, hash4}}) - logs, _ := filter.Logs(context.Background()) - if len(logs) != 4 { - t.Error("expected 4 log, got", len(logs)) - } + // Generate pending block + pchain, preceipts := core.GenerateChain(gspec.Config, chain[len(chain)-1], ethash.NewFaker(), db, 1, func(i int, gen *core.BlockGen) { + data, err := contractABI.Pack("log1", hash5.Big()) + if err != nil { + t.Fatal(err) + } + tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{ + Nonce: 5, + GasPrice: gen.BaseFee(), + Gas: 30000, + To: &contract, + Data: data, + }), signer, key1) + gen.AddTx(tx) + }) + sys.backend.(*testBackend).pendingBlock = pchain[0] + sys.backend.(*testBackend).pendingReceipts = preceipts[0] for i, tc := range []struct { - f *Filter - wantHashes []common.Hash + f *Filter + want string + err string }{ { - sys.NewRangeFilter(900, 999, []common.Address{addr}, [][]common.Hash{{hash3}}), - []common.Hash{hash3}, + f: sys.NewBlockFilter(chain[2].Hash(), []common.Address{contract}, nil), + want: `[{"address":"0xfe00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696332","0x0000000000000000000000000000000000000000000000000000746f70696331"],"data":"0x","blockNumber":"0x3","transactionHash":"0xdefe471992a07a02acdfbe33edaae22fbb86d7d3cec3f1b8e4e77702fb3acc1d","transactionIndex":"0x0","blockHash":"0x7a7556792ca7d37882882e2b001fe14833eaf81c2c7f865c9c771ec37a024f6b","logIndex":"0x0","removed":false}]`, }, { - sys.NewRangeFilter(990, -1, []common.Address{addr}, [][]common.Hash{{hash3}}), - []common.Hash{hash3}, + f: sys.NewRangeFilter(0, int64(rpc.LatestBlockNumber), []common.Address{contract}, [][]common.Hash{{hash1, hash2, hash3, hash4}}), + want: `[{"address":"0xfe00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696331"],"data":"0x","blockNumber":"0x2","transactionHash":"0xa8028c655b6423204c8edfbc339f57b042d6bec2b6a61145d76b7c08b4cccd42","transactionIndex":"0x0","blockHash":"0x24417bb49ce44cfad65da68f33b510bf2a129c0d89ccf06acb6958b8585ccf34","logIndex":"0x0","removed":false},{"address":"0xfe00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696332","0x0000000000000000000000000000000000000000000000000000746f70696331"],"data":"0x","blockNumber":"0x3","transactionHash":"0xdefe471992a07a02acdfbe33edaae22fbb86d7d3cec3f1b8e4e77702fb3acc1d","transactionIndex":"0x0","blockHash":"0x7a7556792ca7d37882882e2b001fe14833eaf81c2c7f865c9c771ec37a024f6b","logIndex":"0x0","removed":false},{"address":"0xfe00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696334"],"data":"0x","blockNumber":"0x3e8","transactionHash":"0x9a87842100a638dfa5da8842b4beda691d2fd77b0c84b57f24ecfa9fb208f747","transactionIndex":"0x0","blockHash":"0xb360bad5265261c075ece02d3bf0e39498a6a76310482cdfd90588748e6c5ee0","logIndex":"0x0","removed":false}]`, }, { - sys.NewRangeFilter(1, 10, nil, [][]common.Hash{{hash1, hash2}}), - []common.Hash{hash1, hash2}, + f: sys.NewRangeFilter(900, 999, []common.Address{contract}, [][]common.Hash{{hash3}}), }, { - sys.NewRangeFilter(0, -1, nil, [][]common.Hash{{common.BytesToHash([]byte("fail"))}}), - nil, + f: sys.NewRangeFilter(990, int64(rpc.LatestBlockNumber), []common.Address{contract2}, [][]common.Hash{{hash3}}), + want: `[{"address":"0xff00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696333"],"data":"0x","blockNumber":"0x3e7","transactionHash":"0x53e3675800c6908424b61b35a44e51ca4c73ca603e58a65b32c67968b4f42200","transactionIndex":"0x0","blockHash":"0x2e4620a2b426b0612ec6cad9603f466723edaed87f98c9137405dd4f7a2409ff","logIndex":"0x0","removed":false}]`, }, { - sys.NewRangeFilter(0, -1, []common.Address{common.BytesToAddress([]byte("failmenow"))}, nil), - nil, + f: sys.NewRangeFilter(1, 10, []common.Address{contract}, [][]common.Hash{{hash2}, {hash1}}), + want: `[{"address":"0xfe00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696332","0x0000000000000000000000000000000000000000000000000000746f70696331"],"data":"0x","blockNumber":"0x3","transactionHash":"0xdefe471992a07a02acdfbe33edaae22fbb86d7d3cec3f1b8e4e77702fb3acc1d","transactionIndex":"0x0","blockHash":"0x7a7556792ca7d37882882e2b001fe14833eaf81c2c7f865c9c771ec37a024f6b","logIndex":"0x0","removed":false}]`, }, { - sys.NewRangeFilter(0, -1, nil, [][]common.Hash{{common.BytesToHash([]byte("fail"))}, {hash1}}), - nil, + f: sys.NewRangeFilter(1, 10, nil, [][]common.Hash{{hash1, hash2}}), + want: `[{"address":"0xfe00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696331"],"data":"0x","blockNumber":"0x2","transactionHash":"0xa8028c655b6423204c8edfbc339f57b042d6bec2b6a61145d76b7c08b4cccd42","transactionIndex":"0x0","blockHash":"0x24417bb49ce44cfad65da68f33b510bf2a129c0d89ccf06acb6958b8585ccf34","logIndex":"0x0","removed":false},{"address":"0xff00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696331"],"data":"0x","blockNumber":"0x2","transactionHash":"0xdba3e2ea9a7d690b722d70ee605fd67ba4c00d1d3aecd5cf187a7b92ad8eb3df","transactionIndex":"0x1","blockHash":"0x24417bb49ce44cfad65da68f33b510bf2a129c0d89ccf06acb6958b8585ccf34","logIndex":"0x1","removed":false},{"address":"0xfe00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696332","0x0000000000000000000000000000000000000000000000000000746f70696331"],"data":"0x","blockNumber":"0x3","transactionHash":"0xdefe471992a07a02acdfbe33edaae22fbb86d7d3cec3f1b8e4e77702fb3acc1d","transactionIndex":"0x0","blockHash":"0x7a7556792ca7d37882882e2b001fe14833eaf81c2c7f865c9c771ec37a024f6b","logIndex":"0x0","removed":false}]`, }, { - sys.NewRangeFilter(-1, -1, nil, nil), []common.Hash{hash4}, + f: sys.NewRangeFilter(0, int64(rpc.LatestBlockNumber), nil, [][]common.Hash{{common.BytesToHash([]byte("fail"))}}), }, { - sys.NewRangeFilter(-3, -1, nil, nil), []common.Hash{hash3, hash4}, + f: sys.NewRangeFilter(0, int64(rpc.LatestBlockNumber), []common.Address{common.BytesToAddress([]byte("failmenow"))}, nil), }, { - sys.NewRangeFilter(-3, -3, nil, nil), []common.Hash{hash3}, + f: sys.NewRangeFilter(0, int64(rpc.LatestBlockNumber), nil, [][]common.Hash{{common.BytesToHash([]byte("fail"))}, {hash1}}), }, { - sys.NewRangeFilter(-1, -3, nil, nil), nil, + f: sys.NewRangeFilter(int64(rpc.LatestBlockNumber), int64(rpc.LatestBlockNumber), nil, nil), + want: `[{"address":"0xfe00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696334"],"data":"0x","blockNumber":"0x3e8","transactionHash":"0x9a87842100a638dfa5da8842b4beda691d2fd77b0c84b57f24ecfa9fb208f747","transactionIndex":"0x0","blockHash":"0xb360bad5265261c075ece02d3bf0e39498a6a76310482cdfd90588748e6c5ee0","logIndex":"0x0","removed":false}]`, }, { - sys.NewRangeFilter(-4, -1, nil, nil), nil, + f: sys.NewRangeFilter(int64(rpc.FinalizedBlockNumber), int64(rpc.LatestBlockNumber), nil, nil), + want: `[{"address":"0xff00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696333"],"data":"0x","blockNumber":"0x3e7","transactionHash":"0x53e3675800c6908424b61b35a44e51ca4c73ca603e58a65b32c67968b4f42200","transactionIndex":"0x0","blockHash":"0x2e4620a2b426b0612ec6cad9603f466723edaed87f98c9137405dd4f7a2409ff","logIndex":"0x0","removed":false},{"address":"0xfe00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696334"],"data":"0x","blockNumber":"0x3e8","transactionHash":"0x9a87842100a638dfa5da8842b4beda691d2fd77b0c84b57f24ecfa9fb208f747","transactionIndex":"0x0","blockHash":"0xb360bad5265261c075ece02d3bf0e39498a6a76310482cdfd90588748e6c5ee0","logIndex":"0x0","removed":false}]`, }, { - sys.NewRangeFilter(-4, -4, nil, nil), nil, + f: sys.NewRangeFilter(int64(rpc.FinalizedBlockNumber), int64(rpc.FinalizedBlockNumber), nil, nil), + want: `[{"address":"0xff00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696333"],"data":"0x","blockNumber":"0x3e7","transactionHash":"0x53e3675800c6908424b61b35a44e51ca4c73ca603e58a65b32c67968b4f42200","transactionIndex":"0x0","blockHash":"0x2e4620a2b426b0612ec6cad9603f466723edaed87f98c9137405dd4f7a2409ff","logIndex":"0x0","removed":false}]`, }, { - sys.NewRangeFilter(-1, -4, nil, nil), nil, + f: sys.NewRangeFilter(int64(rpc.LatestBlockNumber), int64(rpc.FinalizedBlockNumber), nil, nil), + }, { + f: sys.NewRangeFilter(int64(rpc.SafeBlockNumber), int64(rpc.LatestBlockNumber), nil, nil), + err: "safe header not found", + }, { + f: sys.NewRangeFilter(int64(rpc.SafeBlockNumber), int64(rpc.SafeBlockNumber), nil, nil), + err: "safe header not found", + }, { + f: sys.NewRangeFilter(int64(rpc.LatestBlockNumber), int64(rpc.SafeBlockNumber), nil, nil), + 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":"0xc7245899e5817f16fa99cf5ad2d9c1e4b98443a565a673ec9c764640443ef037","logIndex":"0x0","removed":false}]`, + }, { + 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":"0xc7245899e5817f16fa99cf5ad2d9c1e4b98443a565a673ec9c764640443ef037","logIndex":"0x0","removed":false}]`, + }, { + f: sys.NewRangeFilter(int64(rpc.PendingBlockNumber), int64(rpc.LatestBlockNumber), nil, nil), + err: "invalid block range", }, } { - logs, _ := tc.f.Logs(context.Background()) - var haveHashes []common.Hash - for _, l := range logs { - haveHashes = append(haveHashes, l.Topics[0]) + logs, err := tc.f.Logs(context.Background()) + if err == nil && tc.err != "" { + t.Fatalf("test %d, expected error %q, got nil", i, tc.err) + } else if err != nil && err.Error() != tc.err { + t.Fatalf("test %d, expected error %q, got %q", i, tc.err, err.Error()) } - if have, want := len(haveHashes), len(tc.wantHashes); have != want { - t.Fatalf("test %d, have %d logs, want %d", i, have, want) - } - if len(haveHashes) == 0 { + if tc.want == "" && len(logs) == 0 { continue } - if !reflect.DeepEqual(tc.wantHashes, haveHashes) { - t.Fatalf("test %d, have %v want %v", i, haveHashes, tc.wantHashes) + have, err := json.Marshal(logs) + if err != nil { + t.Fatal(err) + } + if string(have) != tc.want { + t.Fatalf("test %d, have:\n%s\nwant:\n%s", i, have, tc.want) } } + + t.Run("timeout", func(t *testing.T) { + f := sys.NewRangeFilter(0, -1, nil, nil) + ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(-time.Hour)) + defer cancel() + _, err := f.Logs(ctx) + if err == nil { + t.Fatal("expected error") + } + if err != context.DeadlineExceeded { + t.Fatalf("expected context.DeadlineExceeded, got %v", err) + } + }) } diff --git a/eth/gasprice/feehistory.go b/eth/gasprice/feehistory.go index ee0b0ebcca..226991b24b 100644 --- a/eth/gasprice/feehistory.go +++ b/eth/gasprice/feehistory.go @@ -23,14 +23,14 @@ import ( "fmt" "math" "math/big" - "sort" "sync/atomic" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/consensus/misc" + "github.com/ethereum/go-ethereum/consensus/misc/eip1559" "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 ( @@ -69,20 +69,9 @@ type processedFees struct { } // txGasAndReward is sorted in ascending order based on reward -type ( - txGasAndReward struct { - gasUsed uint64 - reward *big.Int - } - sortGasAndReward []txGasAndReward -) - -func (s sortGasAndReward) Len() int { return len(s) } -func (s sortGasAndReward) Swap(i, j int) { - s[i], s[j] = s[j], s[i] -} -func (s sortGasAndReward) Less(i, j int) bool { - return s[i].reward.Cmp(s[j].reward) < 0 +type txGasAndReward struct { + gasUsed uint64 + reward *big.Int } // processBlock takes a blockFees structure with the blockNumber, the header and optionally @@ -94,7 +83,7 @@ func (oracle *Oracle) processBlock(bf *blockFees, percentiles []float64) { bf.results.baseFee = new(big.Int) } if chainconfig.IsLondon(big.NewInt(int64(bf.blockNumber + 1))) { - bf.results.nextBaseFee = misc.CalcBaseFee(chainconfig, bf.header) + bf.results.nextBaseFee = eip1559.CalcBaseFee(chainconfig, bf.header) } else { bf.results.nextBaseFee = new(big.Int) } @@ -117,12 +106,14 @@ func (oracle *Oracle) processBlock(bf *blockFees, percentiles []float64) { return } - sorter := make(sortGasAndReward, len(bf.block.Transactions())) + sorter := make([]txGasAndReward, len(bf.block.Transactions())) for i, tx := range bf.block.Transactions() { reward, _ := tx.EffectiveGasTip(bf.block.BaseFee()) sorter[i] = txGasAndReward{gasUsed: bf.receipts[i].GasUsed, reward: reward} } - sort.Stable(sorter) + slices.SortStableFunc(sorter, func(a, b txGasAndReward) int { + return a.reward.Cmp(b.reward) + }) var txIndex int sumGasUsed := sorter[0].gasUsed diff --git a/eth/gasprice/gasprice.go b/eth/gasprice/gasprice.go index a3dd83d79f..b719649811 100644 --- a/eth/gasprice/gasprice.go +++ b/eth/gasprice/gasprice.go @@ -19,7 +19,6 @@ package gasprice import ( "context" "math/big" - "sort" "sync" "github.com/ethereum/go-ethereum/common" @@ -30,6 +29,7 @@ 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 @@ -208,7 +208,7 @@ func (oracle *Oracle) SuggestTipCap(ctx context.Context) (*big.Int, error) { } price := lastPrice if len(results) > 0 { - sort.Sort(bigIntArray(results)) + slices.SortFunc(results, func(a, b *big.Int) int { return a.Cmp(b) }) price = results[(len(results)-1)*oracle.percentile/100] } if price.Cmp(oracle.maxPrice) > 0 { @@ -227,30 +227,6 @@ type results struct { err error } -type txSorter struct { - txs []*types.Transaction - baseFee *big.Int -} - -func newSorter(txs []*types.Transaction, baseFee *big.Int) *txSorter { - return &txSorter{ - txs: txs, - baseFee: baseFee, - } -} - -func (s *txSorter) Len() int { return len(s.txs) } -func (s *txSorter) Swap(i, j int) { - s.txs[i], s.txs[j] = s.txs[j], s.txs[i] -} -func (s *txSorter) Less(i, j int) bool { - // It's okay to discard the error because a tx would never be - // accepted into a block with an invalid effective tip. - tip1, _ := s.txs[i].EffectiveGasTip(s.baseFee) - tip2, _ := s.txs[j].EffectiveGasTip(s.baseFee) - return tip1.Cmp(tip2) < 0 -} - // getBlockValues calculates the lowest transaction gas price in a given block // and sends it to the result channel. If the block is empty or all transactions // are sent by the miner itself(it doesn't make any sense to include this kind of @@ -267,14 +243,21 @@ func (oracle *Oracle) getBlockValues(ctx context.Context, blockNum uint64, limit signer := types.MakeSigner(oracle.backend.ChainConfig(), block.Number(), block.Time()) // Sort the transaction by effective tip in ascending sort. - txs := make([]*types.Transaction, len(block.Transactions())) - copy(txs, block.Transactions()) - sorter := newSorter(txs, block.BaseFee()) - sort.Sort(sorter) + txs := block.Transactions() + sortedTxs := make([]*types.Transaction, len(txs)) + copy(sortedTxs, txs) + baseFee := block.BaseFee() + slices.SortFunc(sortedTxs, func(a, b *types.Transaction) int { + // It's okay to discard the error because a tx would never be + // accepted into a block with an invalid effective tip. + tip1, _ := a.EffectiveGasTip(baseFee) + tip2, _ := b.EffectiveGasTip(baseFee) + return tip1.Cmp(tip2) + }) var prices []*big.Int - for _, tx := range sorter.txs { - tip, _ := tx.EffectiveGasTip(block.BaseFee()) + for _, tx := range sortedTxs { + tip, _ := tx.EffectiveGasTip(baseFee) if ignoreUnder != nil && tip.Cmp(ignoreUnder) == -1 { continue } @@ -291,9 +274,3 @@ func (oracle *Oracle) getBlockValues(ctx context.Context, blockNum uint64, limit case <-quit: } } - -type bigIntArray []*big.Int - -func (s bigIntArray) Len() int { return len(s) } -func (s bigIntArray) Less(i, j int) bool { return s[i].Cmp(s[j]) < 0 } -func (s bigIntArray) Swap(i, j int) { s[i], s[j] = s[j], s[i] } diff --git a/eth/handler.go b/eth/handler.go index f0b043166e..a629ec5ee9 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -29,6 +29,8 @@ import ( "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" + "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/eth/fetcher" @@ -37,13 +39,20 @@ import ( "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/p2p" + "github.com/ethereum/go-ethereum/trie/triedb/pathdb" ) const ( // txChanSize is the size of channel listening to NewTxsEvent. // The number is referenced from the size of tx pool. txChanSize = 4096 + + // txMaxBroadcastSize is the max size of a transaction that will be broadcasted. + // All transactions with a higher size will be announced and need to be fetched + // by the peer. + txMaxBroadcastSize = 4096 ) var ( @@ -61,12 +70,12 @@ type txPool interface { // tx hash. Get(hash common.Hash) *types.Transaction - // AddRemotes should add the given transactions to the pool. - AddRemotes([]*types.Transaction) []error + // Add should add the given transactions to the pool. + Add(txs []*types.Transaction, local bool, sync bool) []error // Pending should return pending transactions. // The slice should be modifiable by the caller. - Pending(enforceTips bool) map[common.Address]types.Transactions + Pending(enforceTips bool) map[common.Address][]*txpool.LazyTransaction // SubscribeNewTxsEvent should return an event subscription of // NewTxsEvent and send events to the given channel. @@ -117,7 +126,9 @@ type handler struct { chainSync *chainSyncer wg sync.WaitGroup - peerWG sync.WaitGroup + + handlerStartCh chan struct{} + handlerDoneCh chan struct{} } // newHandler returns a handler for all Ethereum chain management protocol. @@ -137,6 +148,8 @@ func newHandler(config *handlerConfig) (*handler, error) { merger: config.Merger, requiredBlocks: config.RequiredBlocks, quitSync: make(chan struct{}), + handlerDoneCh: make(chan struct{}), + handlerStartCh: make(chan struct{}), } if config.Sync == downloader.FullSync { // The database seems empty as the current block is the genesis. Yet the snap @@ -172,7 +185,7 @@ func newHandler(config *handlerConfig) (*handler, error) { } // If we've successfully finished a sync cycle, accept transactions from // the network - h.acceptTxs.Store(true) + h.enableSyncedFeatures() } // Construct the downloader (long sync) h.downloader = downloader.New(config.Database, h.eventMux, h.chain, nil, h.removePeer, success) @@ -261,7 +274,7 @@ func newHandler(config *handlerConfig) (*handler, error) { } n, err := h.chain.InsertChain(blocks) if err == nil { - h.acceptTxs.Store(true) // Mark initial sync done on any fetcher import + h.enableSyncedFeatures() // Mark initial sync done on any fetcher import } return n, err } @@ -274,14 +287,58 @@ func newHandler(config *handlerConfig) (*handler, error) { } return p.RequestTxs(hashes) } - h.txFetcher = fetcher.NewTxFetcher(h.txpool.Has, h.txpool.AddRemotes, fetchTx) + addTxs := func(txs []*types.Transaction) []error { + return h.txpool.Add(txs, false, false) + } + h.txFetcher = fetcher.NewTxFetcher(h.txpool.Has, addTxs, fetchTx) h.chainSync = newChainSyncer(h) return h, nil } +// protoTracker tracks the number of active protocol handlers. +func (h *handler) protoTracker() { + defer h.wg.Done() + var active int + for { + select { + case <-h.handlerStartCh: + active++ + case <-h.handlerDoneCh: + active-- + case <-h.quitSync: + // Wait for all active handlers to finish. + for ; active > 0; active-- { + <-h.handlerDoneCh + } + return + } + } +} + +// incHandlers signals to increment the number of active handlers if not +// quitting. +func (h *handler) incHandlers() bool { + select { + case h.handlerStartCh <- struct{}{}: + return true + case <-h.quitSync: + return false + } +} + +// decHandlers signals to decrement the number of active handlers. +func (h *handler) decHandlers() { + h.handlerDoneCh <- struct{}{} +} + // runEthPeer registers an eth peer into the joint eth/snap peerset, adds it to // various subsystems and starts handling messages. func (h *handler) runEthPeer(peer *eth.Peer, handler eth.Handler) error { + if !h.incHandlers() { + return p2p.DiscQuitting + } + defer h.decHandlers() + // If the peer has a `snap` extension, wait for it to connect so we can have // a uniform initialization/teardown mechanism snap, err := h.peers.waitSnapExtension(peer) @@ -289,12 +346,6 @@ func (h *handler) runEthPeer(peer *eth.Peer, handler eth.Handler) error { peer.Log().Error("Snapshot extension barrier failed", "err", err) return err } - // TODO(karalabe): Not sure why this is needed - if !h.chainSync.handlePeerEvent(peer) { - return p2p.DiscQuitting - } - h.peerWG.Add(1) - defer h.peerWG.Done() // Execute the Ethereum handshake var ( @@ -304,7 +355,7 @@ func (h *handler) runEthPeer(peer *eth.Peer, handler eth.Handler) error { number = head.Number.Uint64() td = h.chain.GetTd(hash, number) ) - forkID := forkid.NewID(h.chain.Config(), genesis.Hash(), number, head.Time) + forkID := forkid.NewID(h.chain.Config(), genesis, number, head.Time) if err := peer.Handshake(h.networkID, td, hash, genesis.Hash(), forkID, h.forkFilter); err != nil { peer.Log().Debug("Ethereum handshake failed", "err", err) return err @@ -350,7 +401,7 @@ func (h *handler) runEthPeer(peer *eth.Peer, handler eth.Handler) error { return err } } - h.chainSync.handlePeerEvent(peer) + h.chainSync.handlePeerEvent() // Propagate existing transactions. new transactions appearing // after this will be sent via broadcasts. @@ -411,10 +462,19 @@ func (h *handler) runEthPeer(peer *eth.Peer, handler eth.Handler) error { // `eth`, all subsystem registrations and lifecycle management will be done by // the main `eth` handler to prevent strange races. func (h *handler) runSnapExtension(peer *snap.Peer, handler snap.Handler) error { - h.peerWG.Add(1) - defer h.peerWG.Done() + if !h.incHandlers() { + return p2p.DiscQuitting + } + defer h.decHandlers() if err := h.peers.registerSnapExtension(peer); err != nil { + if metrics.Enabled { + if peer.Inbound() { + snap.IngressRegistrationErrorMeter.Mark(1) + } else { + snap.EgressRegistrationErrorMeter.Mark(1) + } + } peer.Log().Warn("Snapshot extension registration failed", "err", err) return err } @@ -477,6 +537,10 @@ func (h *handler) Start(maxPeers int) { // start sync handlers h.wg.Add(1) go h.chainSync.loop() + + // start peer handler tracker + h.wg.Add(1) + go h.protoTracker() } func (h *handler) Stop() { @@ -486,14 +550,13 @@ func (h *handler) Stop() { // Quit chainSync and txsync64. // After this is done, no new peers will be accepted. close(h.quitSync) - h.wg.Wait() // Disconnect existing sessions. // This also closes the gate for any new registrations on the peer set. // sessions which are already established but not added to h.peers yet // will exit when they try to register. h.peers.close() - h.peerWG.Wait() + h.wg.Wait() log.Info("Ethereum protocol stopped") } @@ -560,8 +623,12 @@ func (h *handler) BroadcastTransactions(txs types.Transactions) { // Broadcast transactions to a batch of peers not knowing about it for _, tx := range txs { peers := h.peers.peersWithoutTransaction(tx.Hash()) + + var numDirect int + if tx.Size() <= txMaxBroadcastSize { + numDirect = int(math.Sqrt(float64(len(peers)))) + } // Send the tx unconditionally to a subset of our peers - numDirect := int(math.Sqrt(float64(len(peers)))) for _, peer := range peers[:numDirect] { txset[peer] = append(txset[peer], tx.Hash()) } @@ -609,3 +676,12 @@ func (h *handler) txBroadcastLoop() { } } } + +// enableSyncedFeatures enables the post-sync functionalities when the initial +// sync is finished. +func (h *handler) enableSyncedFeatures() { + h.acceptTxs.Store(true) + if h.chain.TrieDB().Scheme() == rawdb.PathScheme { + h.chain.TrieDB().SetBufferSize(pathdb.DefaultBufferSize) + } +} diff --git a/eth/handler_eth.go b/eth/handler_eth.go index 00be022d9e..3a5e6608bb 100644 --- a/eth/handler_eth.go +++ b/eth/handler_eth.go @@ -134,7 +134,7 @@ func (h *ethHandler) handleBlockBroadcast(peer *eth.Peer, block *types.Block, td // 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(peer) + h.chainSync.handlePeerEvent() } return nil } diff --git a/eth/handler_eth_test.go b/eth/handler_eth_test.go index fd7df23403..41619fe300 100644 --- a/eth/handler_eth_test.go +++ b/eth/handler_eth_test.go @@ -311,11 +311,10 @@ func testSendTransactions(t *testing.T, protocol uint) { for nonce := range insert { tx := types.NewTransaction(uint64(nonce), common.Address{}, big.NewInt(0), 100000, big.NewInt(0), make([]byte, 10240)) tx, _ = types.SignTx(tx, types.HomesteadSigner{}, testKey) - insert[nonce] = tx } - go handler.txpool.AddRemotes(insert) // Need goroutine to not block on feed - time.Sleep(250 * time.Millisecond) // Wait until tx events get out of the system (can't use events, tx broadcaster races with peer join) + go handler.txpool.Add(insert, false, false) // Need goroutine to not block on feed + time.Sleep(250 * time.Millisecond) // Wait until tx events get out of the system (can't use events, tx broadcaster races with peer join) // Create a source handler to send messages through and a sink peer to receive them p2pSrc, p2pSink := p2p.MsgPipe() @@ -437,10 +436,9 @@ func testTransactionPropagation(t *testing.T, protocol uint) { for nonce := range txs { tx := types.NewTransaction(uint64(nonce), common.Address{}, big.NewInt(0), 100000, big.NewInt(0), nil) tx, _ = types.SignTx(tx, types.HomesteadSigner{}, testKey) - txs[nonce] = tx } - source.txpool.AddRemotes(txs) + source.txpool.Add(txs, false, false) // Iterate through all the sinks and ensure they all got the transactions for i := range sinks { diff --git a/eth/handler_test.go b/eth/handler_test.go index 8939e53a95..2e0a988452 100644 --- a/eth/handler_test.go +++ b/eth/handler_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/txpool" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" @@ -74,13 +75,12 @@ func (p *testTxPool) Has(hash common.Hash) bool { func (p *testTxPool) Get(hash common.Hash) *types.Transaction { p.lock.Lock() defer p.lock.Unlock() - return p.pool[hash] } -// AddRemotes appends a batch of transactions to the pool, and notifies any +// Add appends a batch of transactions to the pool, and notifies any // listeners if the addition channel is non nil -func (p *testTxPool) AddRemotes(txs []*types.Transaction) []error { +func (p *testTxPool) Add(txs []*types.Transaction, local bool, sync bool) []error { p.lock.Lock() defer p.lock.Unlock() @@ -92,11 +92,11 @@ func (p *testTxPool) AddRemotes(txs []*types.Transaction) []error { } // Pending returns all the transactions known to the pool -func (p *testTxPool) Pending(enforceTips bool) map[common.Address]types.Transactions { +func (p *testTxPool) Pending(enforceTips bool) map[common.Address][]*txpool.LazyTransaction { p.lock.RLock() defer p.lock.RUnlock() - batches := make(map[common.Address]types.Transactions) + batches := make(map[common.Address][]*types.Transaction) for _, tx := range p.pool { from, _ := types.Sender(types.HomesteadSigner{}, tx) batches[from] = append(batches[from], tx) @@ -104,7 +104,19 @@ func (p *testTxPool) Pending(enforceTips bool) map[common.Address]types.Transact for _, batch := range batches { sort.Sort(types.TxByNonce(batch)) } - return batches + pending := make(map[common.Address][]*txpool.LazyTransaction) + for addr, batch := range batches { + for _, tx := range batch { + pending[addr] = append(pending[addr], &txpool.LazyTransaction{ + Hash: tx.Hash(), + Tx: tx, + Time: tx.Time(), + GasFeeCap: tx.GasFeeCap(), + GasTipCap: tx.GasTipCap(), + }) + } + } + return pending } // SubscribeNewTxsEvent should return an event subscription of NewTxsEvent and diff --git a/eth/protocols/eth/discovery.go b/eth/protocols/eth/discovery.go index 87857244b5..a7bdd47daf 100644 --- a/eth/protocols/eth/discovery.go +++ b/eth/protocols/eth/discovery.go @@ -61,6 +61,6 @@ func StartENRUpdater(chain *core.BlockChain, ln *enode.LocalNode) { func currentENREntry(chain *core.BlockChain) *enrEntry { head := chain.CurrentHeader() return &enrEntry{ - ForkID: forkid.NewID(chain.Config(), chain.Genesis().Hash(), head.Number.Uint64(), head.Time), + ForkID: forkid.NewID(chain.Config(), chain.Genesis(), head.Number.Uint64(), head.Time), } } diff --git a/eth/protocols/eth/handler.go b/eth/protocols/eth/handler.go index 2f2dd1cf6a..b2ce883bc5 100644 --- a/eth/protocols/eth/handler.go +++ b/eth/protocols/eth/handler.go @@ -23,6 +23,7 @@ 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/types" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/p2p" @@ -95,11 +96,15 @@ type TxPool interface { // MakeProtocols constructs the P2P protocol definitions for `eth`. func MakeProtocols(backend Backend, network uint64, dnsdisc enode.Iterator) []p2p.Protocol { - protocols := make([]p2p.Protocol, len(ProtocolVersions)) - for i, version := range ProtocolVersions { + protocols := make([]p2p.Protocol, 0, len(ProtocolVersions)) + for _, version := range ProtocolVersions { version := version // Closure - protocols[i] = p2p.Protocol{ + // Path scheme does not support GetNodeData, don't advertise eth66 on it + if version <= ETH66 && backend.Chain().TrieDB().Scheme() == rawdb.PathScheme { + continue + } + protocols = append(protocols, p2p.Protocol{ Name: ProtocolName, Version: version, Length: protocolLengths[version], @@ -119,7 +124,7 @@ func MakeProtocols(backend Backend, network uint64, dnsdisc enode.Iterator) []p2 }, Attributes: []enr.Entry{currentENREntry(backend.Chain())}, DialCandidates: dnsdisc, - } + }) } return protocols } @@ -127,7 +132,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, Rinkeby=4, Goerli=5) + Network uint64 `json:"network"` // Ethereum network ID (1=Mainnet, Goerli=5) 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/eth/protocols/eth/handler_test.go b/eth/protocols/eth/handler_test.go index bbb9866bd3..bf2874721a 100644 --- a/eth/protocols/eth/handler_test.go +++ b/eth/protocols/eth/handler_test.go @@ -30,6 +30,7 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "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" @@ -111,21 +112,24 @@ func newTestBackendWithGenerator(blocks int, shanghai bool, generator func(int, panic(err) } for _, block := range bs { - chain.StateCache().TrieDB().Commit(block.Root(), false) + chain.TrieDB().Commit(block.Root(), false) } - txconfig := txpool.DefaultConfig + txconfig := legacypool.DefaultConfig txconfig.Journal = "" // Don't litter the disk with test journals + pool := legacypool.New(txconfig, chain) + txpool, _ := txpool.New(new(big.Int).SetUint64(txconfig.PriceLimit), chain, []txpool.SubPool{pool}) + return &testBackend{ db: db, chain: chain, - txpool: txpool.NewTxPool(txconfig, params.TestChainConfig, chain), + txpool: txpool, } } // close tears down the transaction pool and chain behind the mock backend. func (b *testBackend) close() { - b.txpool.Stop() + b.txpool.Close() b.chain.Stop() } diff --git a/eth/protocols/eth/handlers.go b/eth/protocols/eth/handlers.go index 74e514b863..da741791bc 100644 --- a/eth/protocols/eth/handlers.go +++ b/eth/protocols/eth/handlers.go @@ -22,6 +22,7 @@ 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/types" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" @@ -246,6 +247,10 @@ func handleGetNodeData66(backend Backend, msg Decoder, peer *Peer) error { // ServiceGetNodeDataQuery assembles the response to a node data query. It is // exposed to allow external packages to test protocol behavior. func ServiceGetNodeDataQuery(chain *core.BlockChain, query GetNodeDataPacket) [][]byte { + // Request nodes by hash is not supported in path-based scheme. + if chain.TrieDB().Scheme() == rawdb.PathScheme { + return nil + } // Gather state data until the fetch or network limits is reached var ( bytes int @@ -257,7 +262,7 @@ func ServiceGetNodeDataQuery(chain *core.BlockChain, query GetNodeDataPacket) [] break } // Retrieve the requested state entry - entry, err := chain.TrieNode(hash) + entry, err := chain.TrieDB().Node(hash) if len(entry) == 0 || err != nil { // Read the contract code with prefix only to save unnecessary lookups. entry, err = chain.ContractCodeWithPrefix(hash) diff --git a/eth/protocols/eth/handshake.go b/eth/protocols/eth/handshake.go index 9a2769fa0d..ea16a85b1e 100644 --- a/eth/protocols/eth/handshake.go +++ b/eth/protocols/eth/handshake.go @@ -17,12 +17,14 @@ package eth import ( + "errors" "fmt" "math/big" "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/forkid" + "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/p2p" ) @@ -59,9 +61,11 @@ func (p *Peer) Handshake(network uint64, td *big.Int, head common.Hash, genesis select { case err := <-errc: if err != nil { + markError(p, err) return err } case <-timeout.C: + markError(p, p2p.DiscReadTimeout) return p2p.DiscReadTimeout } } @@ -105,3 +109,25 @@ func (p *Peer) readStatus(network uint64, status *StatusPacket, genesis common.H } return nil } + +// markError registers the error with the corresponding metric. +func markError(p *Peer, err error) { + if !metrics.Enabled { + return + } + m := meters.get(p.Inbound()) + switch errors.Unwrap(err) { + case errNetworkIDMismatch: + m.networkIDMismatch.Mark(1) + case errProtocolVersionMismatch: + m.protocolVersionMismatch.Mark(1) + case errGenesisMismatch: + m.genesisMismatch.Mark(1) + case errForkIDRejected: + m.forkidRejected.Mark(1) + case p2p.DiscReadTimeout: + m.timeoutError.Mark(1) + default: + m.peerError.Mark(1) + } +} diff --git a/eth/protocols/eth/handshake_test.go b/eth/protocols/eth/handshake_test.go index 5c6727d91c..dca66e0c57 100644 --- a/eth/protocols/eth/handshake_test.go +++ b/eth/protocols/eth/handshake_test.go @@ -40,7 +40,7 @@ func testHandshake(t *testing.T, protocol uint) { genesis = backend.chain.Genesis() head = backend.chain.CurrentBlock() td = backend.chain.GetTd(head.Hash(), head.Number.Uint64()) - forkID = forkid.NewID(backend.chain.Config(), backend.chain.Genesis().Hash(), backend.chain.CurrentHeader().Number.Uint64(), backend.chain.CurrentHeader().Time) + forkID = forkid.NewID(backend.chain.Config(), backend.chain.Genesis(), backend.chain.CurrentHeader().Number.Uint64(), backend.chain.CurrentHeader().Time) ) tests := []struct { code uint64 diff --git a/eth/protocols/eth/metrics.go b/eth/protocols/eth/metrics.go new file mode 100644 index 0000000000..5e0aee39f8 --- /dev/null +++ b/eth/protocols/eth/metrics.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 eth + +import "github.com/ethereum/go-ethereum/metrics" + +// meters stores ingress and egress handshake meters. +var meters bidirectionalMeters + +// bidirectionalMeters stores ingress and egress handshake meters. +type bidirectionalMeters struct { + ingress *hsMeters + egress *hsMeters +} + +// get returns the corresponding meter depending if ingress or egress is +// desired. +func (h *bidirectionalMeters) get(ingress bool) *hsMeters { + if ingress { + return h.ingress + } + return h.egress +} + +// hsMeters is a collection of meters which track metrics related to the +// eth subprotocol handshake. +type hsMeters struct { + // peerError measures the number of errors related to incorrect peer + // behaviour, such as invalid message code, size, encoding, etc. + peerError metrics.Meter + + // timeoutError measures the number of timeouts. + timeoutError metrics.Meter + + // networkIDMismatch measures the number of network id mismatch errors. + networkIDMismatch metrics.Meter + + // protocolVersionMismatch measures the number of differing protocol + // versions. + protocolVersionMismatch metrics.Meter + + // genesisMismatch measures the number of differing genesises. + genesisMismatch metrics.Meter + + // forkidRejected measures the number of differing forkids. + forkidRejected metrics.Meter +} + +// newHandshakeMeters registers and returns handshake meters for the given +// base. +func newHandshakeMeters(base string) *hsMeters { + return &hsMeters{ + peerError: metrics.NewRegisteredMeter(base+"error/peer", nil), + timeoutError: metrics.NewRegisteredMeter(base+"error/timeout", nil), + networkIDMismatch: metrics.NewRegisteredMeter(base+"error/network", nil), + protocolVersionMismatch: metrics.NewRegisteredMeter(base+"error/version", nil), + genesisMismatch: metrics.NewRegisteredMeter(base+"error/genesis", nil), + forkidRejected: metrics.NewRegisteredMeter(base+"error/forkid", nil), + } +} + +func init() { + meters = bidirectionalMeters{ + ingress: newHandshakeMeters("eth/protocols/eth/ingress/handshake/"), + egress: newHandshakeMeters("eth/protocols/eth/egress/handshake/"), + } +} diff --git a/eth/protocols/eth/protocol.go b/eth/protocols/eth/protocol.go index 0d4b368988..4b9f5ad6ba 100644 --- a/eth/protocols/eth/protocol.go +++ b/eth/protocols/eth/protocol.go @@ -59,13 +59,13 @@ const ( GetBlockBodiesMsg = 0x05 BlockBodiesMsg = 0x06 NewBlockMsg = 0x07 + NewPooledTransactionHashesMsg = 0x08 + GetPooledTransactionsMsg = 0x09 + PooledTransactionsMsg = 0x0a GetNodeDataMsg = 0x0d NodeDataMsg = 0x0e GetReceiptsMsg = 0x0f ReceiptsMsg = 0x10 - NewPooledTransactionHashesMsg = 0x08 - GetPooledTransactionsMsg = 0x09 - PooledTransactionsMsg = 0x0a ) var ( @@ -363,6 +363,17 @@ func (*BlockBodiesPacket) Kind() byte { return BlockBodiesMsg } func (*NewBlockPacket) Name() string { return "NewBlock" } func (*NewBlockPacket) Kind() byte { return NewBlockMsg } +func (*NewPooledTransactionHashesPacket66) Name() string { return "NewPooledTransactionHashes" } +func (*NewPooledTransactionHashesPacket66) Kind() byte { return NewPooledTransactionHashesMsg } +func (*NewPooledTransactionHashesPacket68) Name() string { return "NewPooledTransactionHashes" } +func (*NewPooledTransactionHashesPacket68) Kind() byte { return NewPooledTransactionHashesMsg } + +func (*GetPooledTransactionsPacket) Name() string { return "GetPooledTransactions" } +func (*GetPooledTransactionsPacket) Kind() byte { return GetPooledTransactionsMsg } + +func (*PooledTransactionsPacket) Name() string { return "PooledTransactions" } +func (*PooledTransactionsPacket) Kind() byte { return PooledTransactionsMsg } + func (*GetNodeDataPacket) Name() string { return "GetNodeData" } func (*GetNodeDataPacket) Kind() byte { return GetNodeDataMsg } @@ -374,15 +385,3 @@ func (*GetReceiptsPacket) Kind() byte { return GetReceiptsMsg } func (*ReceiptsPacket) Name() string { return "Receipts" } func (*ReceiptsPacket) Kind() byte { return ReceiptsMsg } - -func (*NewPooledTransactionHashesPacket66) Name() string { return "NewPooledTransactionHashes" } -func (*NewPooledTransactionHashesPacket66) Kind() byte { return NewPooledTransactionHashesMsg } - -func (*NewPooledTransactionHashesPacket68) Name() string { return "NewPooledTransactionHashes" } -func (*NewPooledTransactionHashesPacket68) Kind() byte { return NewPooledTransactionHashesMsg } - -func (*GetPooledTransactionsPacket) Name() string { return "GetPooledTransactions" } -func (*GetPooledTransactionsPacket) Kind() byte { return GetPooledTransactionsMsg } - -func (*PooledTransactionsPacket) Name() string { return "PooledTransactions" } -func (*PooledTransactionsPacket) Kind() byte { return PooledTransactionsMsg } diff --git a/eth/protocols/snap/handler.go b/eth/protocols/snap/handler.go index 55781ac54b..b2fd03766e 100644 --- a/eth/protocols/snap/handler.go +++ b/eth/protocols/snap/handler.go @@ -284,7 +284,7 @@ func ServiceGetAccountRangeQuery(chain *core.BlockChain, req *GetAccountRangePac req.Bytes = softResponseLimit } // Retrieve the requested state and bail out if non existent - tr, err := trie.New(trie.StateTrieID(req.Root), chain.StateCache().TrieDB()) + tr, err := trie.New(trie.StateTrieID(req.Root), chain.TrieDB()) if err != nil { return nil, nil } @@ -322,12 +322,12 @@ func ServiceGetAccountRangeQuery(chain *core.BlockChain, req *GetAccountRangePac // Generate the Merkle proofs for the first and last account proof := light.NewNodeSet() - if err := tr.Prove(req.Origin[:], 0, proof); err != nil { + if err := tr.Prove(req.Origin[:], proof); err != nil { log.Warn("Failed to prove account range", "origin", req.Origin, "err", err) return nil, nil } if last != (common.Hash{}) { - if err := tr.Prove(last[:], 0, proof); err != nil { + if err := tr.Prove(last[:], proof); err != nil { log.Warn("Failed to prove account range", "last", last, "err", err) return nil, nil } @@ -414,7 +414,7 @@ func ServiceGetStorageRangesQuery(chain *core.BlockChain, req *GetStorageRangesP if origin != (common.Hash{}) || (abort && len(storage) > 0) { // Request started at a non-zero hash or was capped prematurely, add // the endpoint Merkle proofs - accTrie, err := trie.NewStateTrie(trie.StateTrieID(req.Root), chain.StateCache().TrieDB()) + accTrie, err := trie.NewStateTrie(trie.StateTrieID(req.Root), chain.TrieDB()) if err != nil { return nil, nil } @@ -423,17 +423,17 @@ func ServiceGetStorageRangesQuery(chain *core.BlockChain, req *GetStorageRangesP return nil, nil } id := trie.StorageTrieID(req.Root, account, acc.Root) - stTrie, err := trie.NewStateTrie(id, chain.StateCache().TrieDB()) + stTrie, err := trie.NewStateTrie(id, chain.TrieDB()) if err != nil { return nil, nil } proof := light.NewNodeSet() - if err := stTrie.Prove(origin[:], 0, proof); err != nil { + if err := stTrie.Prove(origin[:], proof); err != nil { log.Warn("Failed to prove storage range", "origin", req.Origin, "err", err) return nil, nil } if last != (common.Hash{}) { - if err := stTrie.Prove(last[:], 0, proof); err != nil { + if err := stTrie.Prove(last[:], proof); err != nil { log.Warn("Failed to prove storage range", "last", last, "err", err) return nil, nil } @@ -487,7 +487,7 @@ func ServiceGetTrieNodesQuery(chain *core.BlockChain, req *GetTrieNodesPacket, s req.Bytes = softResponseLimit } // Make sure we have the state associated with the request - triedb := chain.StateCache().TrieDB() + triedb := chain.TrieDB() accTrie, err := trie.NewStateTrie(trie.StateTrieID(req.Root), triedb) if err != nil { diff --git a/rpc/constants_unix.go b/eth/protocols/snap/metrics.go similarity index 62% rename from rpc/constants_unix.go rename to eth/protocols/snap/metrics.go index 1f04d15d7f..a9f35ca447 100644 --- a/rpc/constants_unix.go +++ b/eth/protocols/snap/metrics.go @@ -1,4 +1,4 @@ -// Copyright 2019 The go-ethereum Authors +// 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 @@ -14,21 +14,16 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -//go:build darwin || dragonfly || freebsd || linux || nacl || netbsd || openbsd || solaris -// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris +package snap -package rpc - -/* -#include - -int max_socket_path_size() { -struct sockaddr_un s; -return sizeof(s.sun_path); -} -*/ -import "C" +import ( + metrics "github.com/ethereum/go-ethereum/metrics" +) var ( - max_path_size = C.max_socket_path_size() + ingressRegistrationErrorName = "eth/protocols/snap/ingress/registration/error" + egressRegistrationErrorName = "eth/protocols/snap/egress/registration/error" + + IngressRegistrationErrorMeter = metrics.NewRegisteredMeter(ingressRegistrationErrorName, nil) + EgressRegistrationErrorMeter = metrics.NewRegisteredMeter(egressRegistrationErrorName, nil) ) diff --git a/eth/protocols/snap/protocol.go b/eth/protocols/snap/protocol.go index 60a254f396..0db206b081 100644 --- a/eth/protocols/snap/protocol.go +++ b/eth/protocols/snap/protocol.go @@ -21,7 +21,7 @@ import ( "fmt" "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/rlp" ) @@ -104,7 +104,7 @@ func (p *AccountRangePacket) Unpack() ([]common.Hash, [][]byte, error) { accounts = make([][]byte, len(p.Accounts)) ) for i, acc := range p.Accounts { - val, err := snapshot.FullAccountRLP(acc.Body) + val, err := types.FullAccountRLP(acc.Body) if err != nil { return nil, nil, fmt.Errorf("invalid account %x: %v", acc.Body, err) } diff --git a/eth/protocols/snap/sync.go b/eth/protocols/snap/sync.go index e99eb88436..0f5f2ccdfe 100644 --- a/eth/protocols/snap/sync.go +++ b/eth/protocols/snap/sync.go @@ -33,7 +33,6 @@ 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/state/snapshot" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" @@ -731,6 +730,8 @@ func (s *Syncer) loadSyncStatus() { } s.tasks = progress.Tasks for _, task := range s.tasks { + task := task // closure for task.genBatch in the stacktrie writer callback + task.genBatch = ethdb.HookedBatch{ Batch: s.db.NewBatch(), OnPut: func(key []byte, value []byte) { @@ -742,6 +743,8 @@ func (s *Syncer) loadSyncStatus() { }) for accountHash, subtasks := range task.SubTasks { for _, subtask := range subtasks { + subtask := subtask // closure for subtask.genBatch in the stacktrie writer callback + subtask.genBatch = ethdb.HookedBatch{ Batch: s.db.NewBatch(), OnPut: func(key []byte, value []byte) { @@ -2277,13 +2280,13 @@ func (s *Syncer) forwardAccountTask(task *accountTask) { if task.needCode[i] || task.needState[i] { break } - slim := snapshot.SlimAccountRLP(res.accounts[i].Nonce, res.accounts[i].Balance, res.accounts[i].Root, res.accounts[i].CodeHash) + 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] { - full, err := snapshot.FullAccountRLP(slim) // TODO(karalabe): Slim parsing can be omitted + full, err := types.FullAccountRLP(slim) // TODO(karalabe): Slim parsing can be omitted if err != nil { panic(err) // Really shouldn't ever happen } @@ -2902,7 +2905,7 @@ func (s *Syncer) onHealState(paths [][]byte, value []byte) error { if err := rlp.DecodeBytes(value, &account); err != nil { return nil // Returning the error here would drop the remote peer } - blob := snapshot.SlimAccountRLP(account.Nonce, account.Balance, account.Root, account.CodeHash) + blob := types.SlimAccountRLP(account) rawdb.WriteAccountSnapshot(s.stateWriter, common.BytesToHash(paths[0]), blob) s.accountHealed += 1 s.accountHealedBytes += common.StorageSize(1 + common.HashLength + len(blob)) diff --git a/eth/protocols/snap/sync_test.go b/eth/protocols/snap/sync_test.go index 58cde8d1eb..1514ad4e13 100644 --- a/eth/protocols/snap/sync_test.go +++ b/eth/protocols/snap/sync_test.go @@ -22,7 +22,6 @@ import ( "encoding/binary" "fmt" "math/big" - "sort" "sync" "testing" "time" @@ -36,8 +35,10 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" + "github.com/ethereum/go-ethereum/trie/triedb/pathdb" "github.com/ethereum/go-ethereum/trie/trienode" "golang.org/x/crypto/sha3" + "golang.org/x/exp/slices" ) func TestHashing(t *testing.T) { @@ -127,9 +128,9 @@ type testPeer struct { remote *Syncer logger log.Logger accountTrie *trie.Trie - accountValues entrySlice + accountValues []*kv storageTries map[common.Hash]*trie.Trie - storageValues map[common.Hash]entrySlice + storageValues map[common.Hash][]*kv accountRequestHandler accountHandlerFunc storageRequestHandler storageHandlerFunc @@ -273,12 +274,12 @@ func createAccountRequestResponse(t *testPeer, root common.Hash, origin common.H // Actually, we need to supply proofs either way! This seems to be an implementation // quirk in go-ethereum proof := light.NewNodeSet() - if err := t.accountTrie.Prove(origin[:], 0, proof); err != nil { + if err := t.accountTrie.Prove(origin[:], proof); err != nil { t.logger.Error("Could not prove inexistence of origin", "origin", origin, "error", err) } if len(keys) > 0 { lastK := (keys[len(keys)-1])[:] - if err := t.accountTrie.Prove(lastK, 0, proof); err != nil { + if err := t.accountTrie.Prove(lastK, proof); err != nil { t.logger.Error("Could not prove last item", "error", err) } } @@ -358,12 +359,12 @@ func createStorageRequestResponse(t *testPeer, root common.Hash, accounts []comm // Here's a potential gotcha: when constructing the proof, we cannot // use the 'origin' slice directly, but must use the full 32-byte // hash form. - if err := stTrie.Prove(originHash[:], 0, proof); err != nil { + if err := stTrie.Prove(originHash[:], proof); err != nil { t.logger.Error("Could not prove inexistence of origin", "origin", originHash, "error", err) } if len(keys) > 0 { lastK := (keys[len(keys)-1])[:] - if err := stTrie.Prove(lastK, 0, proof); err != nil { + if err := stTrie.Prove(lastK, proof); err != nil { t.logger.Error("Could not prove last item", "error", err) } } @@ -416,13 +417,13 @@ func createStorageRequestResponseAlwaysProve(t *testPeer, root common.Hash, acco // Here's a potential gotcha: when constructing the proof, we cannot // use the 'origin' slice directly, but must use the full 32-byte // hash form. - if err := stTrie.Prove(origin[:], 0, proof); err != nil { + if err := stTrie.Prove(origin[:], proof); err != nil { t.logger.Error("Could not prove inexistence of origin", "origin", origin, "error", err) } if len(keys) > 0 { lastK := (keys[len(keys)-1])[:] - if err := stTrie.Prove(lastK, 0, proof); err != nil { + if err := stTrie.Prove(lastK, proof); err != nil { t.logger.Error("Could not prove last item", "error", err) } } @@ -561,6 +562,11 @@ func noProofStorageRequestHandler(t *testPeer, requestId uint64, root common.Has func TestSyncBloatedProof(t *testing.T) { t.Parallel() + testSyncBloatedProof(t, rawdb.HashScheme) + testSyncBloatedProof(t, rawdb.PathScheme) +} + +func testSyncBloatedProof(t *testing.T, scheme string) { var ( once sync.Once cancel = make(chan struct{}) @@ -570,7 +576,7 @@ func TestSyncBloatedProof(t *testing.T) { }) } ) - nodeScheme, sourceAccountTrie, elems := makeAccountTrieNoStorage(100) + nodeScheme, sourceAccountTrie, elems := makeAccountTrieNoStorage(100, scheme) source := newTestPeer("source", t, term) source.accountTrie = sourceAccountTrie.Copy() source.accountValues = elems @@ -594,12 +600,12 @@ func TestSyncBloatedProof(t *testing.T) { } // The proofs proof := light.NewNodeSet() - if err := t.accountTrie.Prove(origin[:], 0, proof); err != nil { + if err := t.accountTrie.Prove(origin[:], proof); err != nil { t.logger.Error("Could not prove origin", "origin", origin, "error", err) } // The bloat: add proof of every single element for _, entry := range t.accountValues { - if err := t.accountTrie.Prove(entry.k, 0, proof); err != nil { + if err := t.accountTrie.Prove(entry.k, proof); err != nil { t.logger.Error("Could not prove item", "error", err) } } @@ -638,6 +644,11 @@ func setupSyncer(scheme string, peers ...*testPeer) *Syncer { func TestSync(t *testing.T) { t.Parallel() + testSync(t, rawdb.HashScheme) + testSync(t, rawdb.PathScheme) +} + +func testSync(t *testing.T, scheme string) { var ( once sync.Once cancel = make(chan struct{}) @@ -647,7 +658,7 @@ func TestSync(t *testing.T) { }) } ) - nodeScheme, sourceAccountTrie, elems := makeAccountTrieNoStorage(100) + nodeScheme, sourceAccountTrie, elems := makeAccountTrieNoStorage(100, scheme) mkSource := func(name string) *testPeer { source := newTestPeer(name, t, term) @@ -659,7 +670,7 @@ func TestSync(t *testing.T) { if err := syncer.Sync(sourceAccountTrie.Hash(), cancel); err != nil { t.Fatalf("sync failed: %v", err) } - verifyTrie(syncer.db, sourceAccountTrie.Hash(), t) + verifyTrie(scheme, syncer.db, sourceAccountTrie.Hash(), t) } // TestSyncTinyTriePanic tests a basic sync with one peer, and a tiny trie. This caused a @@ -667,6 +678,11 @@ func TestSync(t *testing.T) { func TestSyncTinyTriePanic(t *testing.T) { t.Parallel() + testSyncTinyTriePanic(t, rawdb.HashScheme) + testSyncTinyTriePanic(t, rawdb.PathScheme) +} + +func testSyncTinyTriePanic(t *testing.T, scheme string) { var ( once sync.Once cancel = make(chan struct{}) @@ -676,7 +692,7 @@ func TestSyncTinyTriePanic(t *testing.T) { }) } ) - nodeScheme, sourceAccountTrie, elems := makeAccountTrieNoStorage(1) + nodeScheme, sourceAccountTrie, elems := makeAccountTrieNoStorage(1, scheme) mkSource := func(name string) *testPeer { source := newTestPeer(name, t, term) @@ -690,13 +706,18 @@ func TestSyncTinyTriePanic(t *testing.T) { t.Fatalf("sync failed: %v", err) } close(done) - verifyTrie(syncer.db, sourceAccountTrie.Hash(), t) + verifyTrie(scheme, syncer.db, sourceAccountTrie.Hash(), t) } // TestMultiSync tests a basic sync with multiple peers func TestMultiSync(t *testing.T) { t.Parallel() + testMultiSync(t, rawdb.HashScheme) + testMultiSync(t, rawdb.PathScheme) +} + +func testMultiSync(t *testing.T, scheme string) { var ( once sync.Once cancel = make(chan struct{}) @@ -706,7 +727,7 @@ func TestMultiSync(t *testing.T) { }) } ) - nodeScheme, sourceAccountTrie, elems := makeAccountTrieNoStorage(100) + nodeScheme, sourceAccountTrie, elems := makeAccountTrieNoStorage(100, scheme) mkSource := func(name string) *testPeer { source := newTestPeer(name, t, term) @@ -720,13 +741,18 @@ func TestMultiSync(t *testing.T) { t.Fatalf("sync failed: %v", err) } close(done) - verifyTrie(syncer.db, sourceAccountTrie.Hash(), t) + verifyTrie(scheme, syncer.db, sourceAccountTrie.Hash(), t) } // TestSyncWithStorage tests basic sync using accounts + storage + code func TestSyncWithStorage(t *testing.T) { t.Parallel() + testSyncWithStorage(t, rawdb.HashScheme) + testSyncWithStorage(t, rawdb.PathScheme) +} + +func testSyncWithStorage(t *testing.T, scheme string) { var ( once sync.Once cancel = make(chan struct{}) @@ -736,7 +762,7 @@ func TestSyncWithStorage(t *testing.T) { }) } ) - nodeScheme, sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(3, 3000, true, false) + nodeScheme, sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(scheme, 3, 3000, true, false) mkSource := func(name string) *testPeer { source := newTestPeer(name, t, term) @@ -752,13 +778,18 @@ func TestSyncWithStorage(t *testing.T) { t.Fatalf("sync failed: %v", err) } close(done) - verifyTrie(syncer.db, sourceAccountTrie.Hash(), t) + verifyTrie(scheme, syncer.db, sourceAccountTrie.Hash(), t) } // TestMultiSyncManyUseless contains one good peer, and many which doesn't return anything valuable at all func TestMultiSyncManyUseless(t *testing.T) { t.Parallel() + testMultiSyncManyUseless(t, rawdb.HashScheme) + testMultiSyncManyUseless(t, rawdb.PathScheme) +} + +func testMultiSyncManyUseless(t *testing.T, scheme string) { var ( once sync.Once cancel = make(chan struct{}) @@ -768,7 +799,7 @@ func TestMultiSyncManyUseless(t *testing.T) { }) } ) - nodeScheme, sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(100, 3000, true, false) + nodeScheme, sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(scheme, 100, 3000, true, false) mkSource := func(name string, noAccount, noStorage, noTrieNode bool) *testPeer { source := newTestPeer(name, t, term) @@ -801,11 +832,18 @@ func TestMultiSyncManyUseless(t *testing.T) { t.Fatalf("sync failed: %v", err) } close(done) - verifyTrie(syncer.db, sourceAccountTrie.Hash(), t) + verifyTrie(scheme, syncer.db, sourceAccountTrie.Hash(), t) } // TestMultiSyncManyUseless contains one good peer, and many which doesn't return anything valuable at all func TestMultiSyncManyUselessWithLowTimeout(t *testing.T) { + t.Parallel() + + testMultiSyncManyUselessWithLowTimeout(t, rawdb.HashScheme) + testMultiSyncManyUselessWithLowTimeout(t, rawdb.PathScheme) +} + +func testMultiSyncManyUselessWithLowTimeout(t *testing.T, scheme string) { var ( once sync.Once cancel = make(chan struct{}) @@ -815,7 +853,7 @@ func TestMultiSyncManyUselessWithLowTimeout(t *testing.T) { }) } ) - nodeScheme, sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(100, 3000, true, false) + nodeScheme, sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(scheme, 100, 3000, true, false) mkSource := func(name string, noAccount, noStorage, noTrieNode bool) *testPeer { source := newTestPeer(name, t, term) @@ -853,11 +891,18 @@ func TestMultiSyncManyUselessWithLowTimeout(t *testing.T) { t.Fatalf("sync failed: %v", err) } close(done) - verifyTrie(syncer.db, sourceAccountTrie.Hash(), t) + verifyTrie(scheme, syncer.db, sourceAccountTrie.Hash(), t) } // TestMultiSyncManyUnresponsive contains one good peer, and many which doesn't respond at all func TestMultiSyncManyUnresponsive(t *testing.T) { + t.Parallel() + + testMultiSyncManyUnresponsive(t, rawdb.HashScheme) + testMultiSyncManyUnresponsive(t, rawdb.PathScheme) +} + +func testMultiSyncManyUnresponsive(t *testing.T, scheme string) { var ( once sync.Once cancel = make(chan struct{}) @@ -867,7 +912,7 @@ func TestMultiSyncManyUnresponsive(t *testing.T) { }) } ) - nodeScheme, sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(100, 3000, true, false) + nodeScheme, sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(scheme, 100, 3000, true, false) mkSource := func(name string, noAccount, noStorage, noTrieNode bool) *testPeer { source := newTestPeer(name, t, term) @@ -903,7 +948,7 @@ func TestMultiSyncManyUnresponsive(t *testing.T) { t.Fatalf("sync failed: %v", err) } close(done) - verifyTrie(syncer.db, sourceAccountTrie.Hash(), t) + verifyTrie(scheme, syncer.db, sourceAccountTrie.Hash(), t) } func checkStall(t *testing.T, term func()) chan struct{} { @@ -925,6 +970,11 @@ func checkStall(t *testing.T, term func()) chan struct{} { func TestSyncBoundaryAccountTrie(t *testing.T) { t.Parallel() + testSyncBoundaryAccountTrie(t, rawdb.HashScheme) + testSyncBoundaryAccountTrie(t, rawdb.PathScheme) +} + +func testSyncBoundaryAccountTrie(t *testing.T, scheme string) { var ( once sync.Once cancel = make(chan struct{}) @@ -934,7 +984,7 @@ func TestSyncBoundaryAccountTrie(t *testing.T) { }) } ) - nodeScheme, sourceAccountTrie, elems := makeBoundaryAccountTrie(3000) + nodeScheme, sourceAccountTrie, elems := makeBoundaryAccountTrie(scheme, 3000) mkSource := func(name string) *testPeer { source := newTestPeer(name, t, term) @@ -952,7 +1002,7 @@ func TestSyncBoundaryAccountTrie(t *testing.T) { t.Fatalf("sync failed: %v", err) } close(done) - verifyTrie(syncer.db, sourceAccountTrie.Hash(), t) + verifyTrie(scheme, syncer.db, sourceAccountTrie.Hash(), t) } // TestSyncNoStorageAndOneCappedPeer tests sync using accounts and no storage, where one peer is @@ -960,6 +1010,11 @@ func TestSyncBoundaryAccountTrie(t *testing.T) { func TestSyncNoStorageAndOneCappedPeer(t *testing.T) { t.Parallel() + testSyncNoStorageAndOneCappedPeer(t, rawdb.HashScheme) + testSyncNoStorageAndOneCappedPeer(t, rawdb.PathScheme) +} + +func testSyncNoStorageAndOneCappedPeer(t *testing.T, scheme string) { var ( once sync.Once cancel = make(chan struct{}) @@ -969,7 +1024,7 @@ func TestSyncNoStorageAndOneCappedPeer(t *testing.T) { }) } ) - nodeScheme, sourceAccountTrie, elems := makeAccountTrieNoStorage(3000) + nodeScheme, sourceAccountTrie, elems := makeAccountTrieNoStorage(3000, scheme) mkSource := func(name string, slow bool) *testPeer { source := newTestPeer(name, t, term) @@ -994,7 +1049,7 @@ func TestSyncNoStorageAndOneCappedPeer(t *testing.T) { t.Fatalf("sync failed: %v", err) } close(done) - verifyTrie(syncer.db, sourceAccountTrie.Hash(), t) + verifyTrie(scheme, syncer.db, sourceAccountTrie.Hash(), t) } // TestSyncNoStorageAndOneCodeCorruptPeer has one peer which doesn't deliver @@ -1002,6 +1057,11 @@ func TestSyncNoStorageAndOneCappedPeer(t *testing.T) { func TestSyncNoStorageAndOneCodeCorruptPeer(t *testing.T) { t.Parallel() + testSyncNoStorageAndOneCodeCorruptPeer(t, rawdb.HashScheme) + testSyncNoStorageAndOneCodeCorruptPeer(t, rawdb.PathScheme) +} + +func testSyncNoStorageAndOneCodeCorruptPeer(t *testing.T, scheme string) { var ( once sync.Once cancel = make(chan struct{}) @@ -1011,7 +1071,7 @@ func TestSyncNoStorageAndOneCodeCorruptPeer(t *testing.T) { }) } ) - nodeScheme, sourceAccountTrie, elems := makeAccountTrieNoStorage(3000) + nodeScheme, sourceAccountTrie, elems := makeAccountTrieNoStorage(3000, scheme) mkSource := func(name string, codeFn codeHandlerFunc) *testPeer { source := newTestPeer(name, t, term) @@ -1034,12 +1094,17 @@ func TestSyncNoStorageAndOneCodeCorruptPeer(t *testing.T) { t.Fatalf("sync failed: %v", err) } close(done) - verifyTrie(syncer.db, sourceAccountTrie.Hash(), t) + verifyTrie(scheme, syncer.db, sourceAccountTrie.Hash(), t) } func TestSyncNoStorageAndOneAccountCorruptPeer(t *testing.T) { t.Parallel() + testSyncNoStorageAndOneAccountCorruptPeer(t, rawdb.HashScheme) + testSyncNoStorageAndOneAccountCorruptPeer(t, rawdb.PathScheme) +} + +func testSyncNoStorageAndOneAccountCorruptPeer(t *testing.T, scheme string) { var ( once sync.Once cancel = make(chan struct{}) @@ -1049,7 +1114,7 @@ func TestSyncNoStorageAndOneAccountCorruptPeer(t *testing.T) { }) } ) - nodeScheme, sourceAccountTrie, elems := makeAccountTrieNoStorage(3000) + nodeScheme, sourceAccountTrie, elems := makeAccountTrieNoStorage(3000, scheme) mkSource := func(name string, accFn accountHandlerFunc) *testPeer { source := newTestPeer(name, t, term) @@ -1072,7 +1137,7 @@ func TestSyncNoStorageAndOneAccountCorruptPeer(t *testing.T) { t.Fatalf("sync failed: %v", err) } close(done) - verifyTrie(syncer.db, sourceAccountTrie.Hash(), t) + verifyTrie(scheme, syncer.db, sourceAccountTrie.Hash(), t) } // TestSyncNoStorageAndOneCodeCappedPeer has one peer which delivers code hashes @@ -1080,6 +1145,11 @@ func TestSyncNoStorageAndOneAccountCorruptPeer(t *testing.T) { func TestSyncNoStorageAndOneCodeCappedPeer(t *testing.T) { t.Parallel() + testSyncNoStorageAndOneCodeCappedPeer(t, rawdb.HashScheme) + testSyncNoStorageAndOneCodeCappedPeer(t, rawdb.PathScheme) +} + +func testSyncNoStorageAndOneCodeCappedPeer(t *testing.T, scheme string) { var ( once sync.Once cancel = make(chan struct{}) @@ -1089,7 +1159,7 @@ func TestSyncNoStorageAndOneCodeCappedPeer(t *testing.T) { }) } ) - nodeScheme, sourceAccountTrie, elems := makeAccountTrieNoStorage(3000) + nodeScheme, sourceAccountTrie, elems := makeAccountTrieNoStorage(3000, scheme) mkSource := func(name string, codeFn codeHandlerFunc) *testPeer { source := newTestPeer(name, t, term) @@ -1123,7 +1193,7 @@ func TestSyncNoStorageAndOneCodeCappedPeer(t *testing.T) { if threshold := 100; counter > threshold { t.Logf("Error, expected < %d invocations, got %d", threshold, counter) } - verifyTrie(syncer.db, sourceAccountTrie.Hash(), t) + verifyTrie(scheme, syncer.db, sourceAccountTrie.Hash(), t) } // TestSyncBoundaryStorageTrie tests sync against a few normal peers, but the @@ -1131,6 +1201,11 @@ func TestSyncNoStorageAndOneCodeCappedPeer(t *testing.T) { func TestSyncBoundaryStorageTrie(t *testing.T) { t.Parallel() + testSyncBoundaryStorageTrie(t, rawdb.HashScheme) + testSyncBoundaryStorageTrie(t, rawdb.PathScheme) +} + +func testSyncBoundaryStorageTrie(t *testing.T, scheme string) { var ( once sync.Once cancel = make(chan struct{}) @@ -1140,7 +1215,7 @@ func TestSyncBoundaryStorageTrie(t *testing.T) { }) } ) - nodeScheme, sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(10, 1000, false, true) + nodeScheme, sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(scheme, 10, 1000, false, true) mkSource := func(name string) *testPeer { source := newTestPeer(name, t, term) @@ -1160,7 +1235,7 @@ func TestSyncBoundaryStorageTrie(t *testing.T) { t.Fatalf("sync failed: %v", err) } close(done) - verifyTrie(syncer.db, sourceAccountTrie.Hash(), t) + verifyTrie(scheme, syncer.db, sourceAccountTrie.Hash(), t) } // TestSyncWithStorageAndOneCappedPeer tests sync using accounts + storage, where one peer is @@ -1168,6 +1243,11 @@ func TestSyncBoundaryStorageTrie(t *testing.T) { func TestSyncWithStorageAndOneCappedPeer(t *testing.T) { t.Parallel() + testSyncWithStorageAndOneCappedPeer(t, rawdb.HashScheme) + testSyncWithStorageAndOneCappedPeer(t, rawdb.PathScheme) +} + +func testSyncWithStorageAndOneCappedPeer(t *testing.T, scheme string) { var ( once sync.Once cancel = make(chan struct{}) @@ -1177,7 +1257,7 @@ func TestSyncWithStorageAndOneCappedPeer(t *testing.T) { }) } ) - nodeScheme, sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(300, 1000, false, false) + nodeScheme, sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(scheme, 300, 1000, false, false) mkSource := func(name string, slow bool) *testPeer { source := newTestPeer(name, t, term) @@ -1202,7 +1282,7 @@ func TestSyncWithStorageAndOneCappedPeer(t *testing.T) { t.Fatalf("sync failed: %v", err) } close(done) - verifyTrie(syncer.db, sourceAccountTrie.Hash(), t) + verifyTrie(scheme, syncer.db, sourceAccountTrie.Hash(), t) } // TestSyncWithStorageAndCorruptPeer tests sync using accounts + storage, where one peer is @@ -1210,6 +1290,11 @@ func TestSyncWithStorageAndOneCappedPeer(t *testing.T) { func TestSyncWithStorageAndCorruptPeer(t *testing.T) { t.Parallel() + testSyncWithStorageAndCorruptPeer(t, rawdb.HashScheme) + testSyncWithStorageAndCorruptPeer(t, rawdb.PathScheme) +} + +func testSyncWithStorageAndCorruptPeer(t *testing.T, scheme string) { var ( once sync.Once cancel = make(chan struct{}) @@ -1219,7 +1304,7 @@ func TestSyncWithStorageAndCorruptPeer(t *testing.T) { }) } ) - nodeScheme, sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(100, 3000, true, false) + nodeScheme, sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(scheme, 100, 3000, true, false) mkSource := func(name string, handler storageHandlerFunc) *testPeer { source := newTestPeer(name, t, term) @@ -1243,12 +1328,17 @@ func TestSyncWithStorageAndCorruptPeer(t *testing.T) { t.Fatalf("sync failed: %v", err) } close(done) - verifyTrie(syncer.db, sourceAccountTrie.Hash(), t) + verifyTrie(scheme, syncer.db, sourceAccountTrie.Hash(), t) } func TestSyncWithStorageAndNonProvingPeer(t *testing.T) { t.Parallel() + testSyncWithStorageAndNonProvingPeer(t, rawdb.HashScheme) + testSyncWithStorageAndNonProvingPeer(t, rawdb.PathScheme) +} + +func testSyncWithStorageAndNonProvingPeer(t *testing.T, scheme string) { var ( once sync.Once cancel = make(chan struct{}) @@ -1258,7 +1348,7 @@ func TestSyncWithStorageAndNonProvingPeer(t *testing.T) { }) } ) - nodeScheme, sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(100, 3000, true, false) + nodeScheme, sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(scheme, 100, 3000, true, false) mkSource := func(name string, handler storageHandlerFunc) *testPeer { source := newTestPeer(name, t, term) @@ -1281,7 +1371,7 @@ func TestSyncWithStorageAndNonProvingPeer(t *testing.T) { t.Fatalf("sync failed: %v", err) } close(done) - verifyTrie(syncer.db, sourceAccountTrie.Hash(), t) + verifyTrie(scheme, syncer.db, sourceAccountTrie.Hash(), t) } // TestSyncWithStorage tests basic sync using accounts + storage + code, against @@ -1290,6 +1380,12 @@ func TestSyncWithStorageAndNonProvingPeer(t *testing.T) { // did not mark the account for healing. func TestSyncWithStorageMisbehavingProve(t *testing.T) { t.Parallel() + + testSyncWithStorageMisbehavingProve(t, rawdb.HashScheme) + testSyncWithStorageMisbehavingProve(t, rawdb.PathScheme) +} + +func testSyncWithStorageMisbehavingProve(t *testing.T, scheme string) { var ( once sync.Once cancel = make(chan struct{}) @@ -1299,7 +1395,7 @@ func TestSyncWithStorageMisbehavingProve(t *testing.T) { }) } ) - nodeScheme, sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorageWithUniqueStorage(10, 30, false) + nodeScheme, sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorageWithUniqueStorage(scheme, 10, 30, false) mkSource := func(name string) *testPeer { source := newTestPeer(name, t, term) @@ -1314,19 +1410,16 @@ func TestSyncWithStorageMisbehavingProve(t *testing.T) { if err := syncer.Sync(sourceAccountTrie.Hash(), cancel); err != nil { t.Fatalf("sync failed: %v", err) } - verifyTrie(syncer.db, sourceAccountTrie.Hash(), t) + verifyTrie(scheme, syncer.db, sourceAccountTrie.Hash(), t) } type kv struct { k, v []byte } -// Some helpers for sorting -type entrySlice []*kv - -func (p entrySlice) Len() int { return len(p) } -func (p entrySlice) Less(i, j int) bool { return bytes.Compare(p[i].k, p[j].k) < 0 } -func (p entrySlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } +func (k *kv) cmp(other *kv) int { + return bytes.Compare(k.k, other.k) +} func key32(i uint64) []byte { key := make([]byte, 32) @@ -1367,11 +1460,11 @@ func getCodeByHash(hash common.Hash) []byte { } // makeAccountTrieNoStorage spits out a trie, along with the leafs -func makeAccountTrieNoStorage(n int) (string, *trie.Trie, entrySlice) { +func makeAccountTrieNoStorage(n int, scheme string) (string, *trie.Trie, []*kv) { var ( - db = trie.NewDatabase(rawdb.NewMemoryDatabase()) + db = trie.NewDatabase(rawdb.NewMemoryDatabase(), newDbConfig(scheme)) accTrie = trie.NewEmpty(db) - entries entrySlice + entries []*kv ) for i := uint64(1); i <= uint64(n); i++ { value, _ := rlp.EncodeToBytes(&types.StateAccount{ @@ -1385,12 +1478,12 @@ func makeAccountTrieNoStorage(n int) (string, *trie.Trie, entrySlice) { accTrie.MustUpdate(elem.k, elem.v) entries = append(entries, elem) } - sort.Sort(entries) + slices.SortFunc(entries, (*kv).cmp) // Commit the state changes into db and re-create the trie // for accessing later. - root, nodes := accTrie.Commit(false) - db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) + root, nodes, _ := accTrie.Commit(false) + db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil) accTrie, _ = trie.New(trie.StateTrieID(root), db) return db.Scheme(), accTrie, entries @@ -1399,12 +1492,12 @@ func makeAccountTrieNoStorage(n int) (string, *trie.Trie, entrySlice) { // makeBoundaryAccountTrie constructs an account trie. Instead of filling // accounts normally, this function will fill a few accounts which have // boundary hash. -func makeBoundaryAccountTrie(n int) (string, *trie.Trie, entrySlice) { +func makeBoundaryAccountTrie(scheme string, n int) (string, *trie.Trie, []*kv) { var ( - entries entrySlice + entries []*kv boundaries []common.Hash - db = trie.NewDatabase(rawdb.NewMemoryDatabase()) + db = trie.NewDatabase(rawdb.NewMemoryDatabase(), newDbConfig(scheme)) accTrie = trie.NewEmpty(db) ) // Initialize boundaries @@ -1447,12 +1540,12 @@ func makeBoundaryAccountTrie(n int) (string, *trie.Trie, entrySlice) { accTrie.MustUpdate(elem.k, elem.v) entries = append(entries, elem) } - sort.Sort(entries) + slices.SortFunc(entries, (*kv).cmp) // Commit the state changes into db and re-create the trie // for accessing later. - root, nodes := accTrie.Commit(false) - db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) + root, nodes, _ := accTrie.Commit(false) + db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil) accTrie, _ = trie.New(trie.StateTrieID(root), db) return db.Scheme(), accTrie, entries @@ -1460,14 +1553,14 @@ func makeBoundaryAccountTrie(n int) (string, *trie.Trie, entrySlice) { // makeAccountTrieWithStorageWithUniqueStorage creates an account trie where each accounts // has a unique storage set. -func makeAccountTrieWithStorageWithUniqueStorage(accounts, slots int, code bool) (string, *trie.Trie, entrySlice, map[common.Hash]*trie.Trie, map[common.Hash]entrySlice) { +func makeAccountTrieWithStorageWithUniqueStorage(scheme string, accounts, slots int, code bool) (string, *trie.Trie, []*kv, map[common.Hash]*trie.Trie, map[common.Hash][]*kv) { var ( - db = trie.NewDatabase(rawdb.NewMemoryDatabase()) + db = trie.NewDatabase(rawdb.NewMemoryDatabase(), newDbConfig(scheme)) accTrie = trie.NewEmpty(db) - entries entrySlice + entries []*kv storageRoots = make(map[common.Hash]common.Hash) storageTries = make(map[common.Hash]*trie.Trie) - storageEntries = make(map[common.Hash]entrySlice) + storageEntries = make(map[common.Hash][]*kv) nodes = trienode.NewMergedNodeSet() ) // Create n accounts in the trie @@ -1494,14 +1587,14 @@ func makeAccountTrieWithStorageWithUniqueStorage(accounts, slots int, code bool) storageRoots[common.BytesToHash(key)] = stRoot storageEntries[common.BytesToHash(key)] = stEntries } - sort.Sort(entries) + 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 - db.Update(root, types.EmptyRootHash, nodes) + db.Update(root, types.EmptyRootHash, 0, nodes, nil) // Re-create tries with new root accTrie, _ = trie.New(trie.StateTrieID(root), db) @@ -1515,14 +1608,14 @@ func makeAccountTrieWithStorageWithUniqueStorage(accounts, slots int, code bool) } // makeAccountTrieWithStorage spits out a trie, along with the leafs -func makeAccountTrieWithStorage(accounts, slots int, code, boundary bool) (string, *trie.Trie, entrySlice, map[common.Hash]*trie.Trie, map[common.Hash]entrySlice) { +func makeAccountTrieWithStorage(scheme string, accounts, slots int, code, boundary bool) (string, *trie.Trie, []*kv, map[common.Hash]*trie.Trie, map[common.Hash][]*kv) { var ( - db = trie.NewDatabase(rawdb.NewMemoryDatabase()) + db = trie.NewDatabase(rawdb.NewMemoryDatabase(), newDbConfig(scheme)) accTrie = trie.NewEmpty(db) - entries entrySlice + entries []*kv storageRoots = make(map[common.Hash]common.Hash) storageTries = make(map[common.Hash]*trie.Trie) - storageEntries = make(map[common.Hash]entrySlice) + storageEntries = make(map[common.Hash][]*kv) nodes = trienode.NewMergedNodeSet() ) // Create n accounts in the trie @@ -1536,7 +1629,7 @@ func makeAccountTrieWithStorage(accounts, slots int, code, boundary bool) (strin var ( stRoot common.Hash stNodes *trienode.NodeSet - stEntries entrySlice + stEntries []*kv ) if boundary { stRoot, stNodes, stEntries = makeBoundaryStorageTrie(common.BytesToHash(key), slots, db) @@ -1559,14 +1652,14 @@ func makeAccountTrieWithStorage(accounts, slots int, code, boundary bool) (strin storageRoots[common.BytesToHash(key)] = stRoot storageEntries[common.BytesToHash(key)] = stEntries } - sort.Sort(entries) + 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 - db.Update(root, types.EmptyRootHash, nodes) + db.Update(root, types.EmptyRootHash, 0, nodes, nil) // Re-create tries with new root accTrie, err := trie.New(trie.StateTrieID(root), db) @@ -1588,9 +1681,9 @@ func makeAccountTrieWithStorage(accounts, slots int, code, boundary bool) (strin // makeStorageTrieWithSeed fills a storage trie with n items, returning the // not-yet-committed trie and the sorted entries. The seeds can be used to ensure // that tries are unique. -func makeStorageTrieWithSeed(owner common.Hash, n, seed uint64, db *trie.Database) (common.Hash, *trienode.NodeSet, entrySlice) { +func makeStorageTrieWithSeed(owner common.Hash, n, seed uint64, db *trie.Database) (common.Hash, *trienode.NodeSet, []*kv) { trie, _ := trie.New(trie.StorageTrieID(types.EmptyRootHash, owner, types.EmptyRootHash), db) - var entries entrySlice + var entries []*kv for i := uint64(1); i <= n; i++ { // store 'x' at slot 'x' slotValue := key32(i + seed) @@ -1603,17 +1696,17 @@ func makeStorageTrieWithSeed(owner common.Hash, n, seed uint64, db *trie.Databas trie.MustUpdate(elem.k, elem.v) entries = append(entries, elem) } - sort.Sort(entries) - root, nodes := trie.Commit(false) + slices.SortFunc(entries, (*kv).cmp) + root, nodes, _ := trie.Commit(false) return root, nodes, entries } // makeBoundaryStorageTrie constructs a storage trie. Instead of filling // storage slots normally, this function will fill a few slots which have // boundary hash. -func makeBoundaryStorageTrie(owner common.Hash, n int, db *trie.Database) (common.Hash, *trienode.NodeSet, entrySlice) { +func makeBoundaryStorageTrie(owner common.Hash, n int, db *trie.Database) (common.Hash, *trienode.NodeSet, []*kv) { var ( - entries entrySlice + entries []*kv boundaries []common.Hash trie, _ = trie.New(trie.StorageTrieID(types.EmptyRootHash, owner, types.EmptyRootHash), db) ) @@ -1654,20 +1747,20 @@ func makeBoundaryStorageTrie(owner common.Hash, n int, db *trie.Database) (commo trie.MustUpdate(elem.k, elem.v) entries = append(entries, elem) } - sort.Sort(entries) - root, nodes := trie.Commit(false) + slices.SortFunc(entries, (*kv).cmp) + root, nodes, _ := trie.Commit(false) return root, nodes, entries } -func verifyTrie(db ethdb.KeyValueStore, root common.Hash, t *testing.T) { +func verifyTrie(scheme string, db ethdb.KeyValueStore, root common.Hash, t *testing.T) { t.Helper() - triedb := trie.NewDatabase(rawdb.NewDatabase(db)) + triedb := trie.NewDatabase(rawdb.NewDatabase(db), newDbConfig(scheme)) accTrie, err := trie.New(trie.StateTrieID(root), triedb) if err != nil { t.Fatal(err) } accounts, slots := 0, 0 - accIt := trie.NewIterator(accTrie.NodeIterator(nil)) + accIt := trie.NewIterator(accTrie.MustNodeIterator(nil)) for accIt.Next() { var acc struct { Nonce uint64 @@ -1685,7 +1778,7 @@ func verifyTrie(db ethdb.KeyValueStore, root common.Hash, t *testing.T) { if err != nil { t.Fatal(err) } - storeIt := trie.NewIterator(storeTrie.NodeIterator(nil)) + storeIt := trie.NewIterator(storeTrie.MustNodeIterator(nil)) for storeIt.Next() { slots++ } @@ -1703,6 +1796,13 @@ func verifyTrie(db ethdb.KeyValueStore, root common.Hash, t *testing.T) { // TestSyncAccountPerformance tests how efficient the snap algo is at minimizing // state healing func TestSyncAccountPerformance(t *testing.T) { + t.Parallel() + + testSyncAccountPerformance(t, rawdb.HashScheme) + testSyncAccountPerformance(t, rawdb.PathScheme) +} + +func testSyncAccountPerformance(t *testing.T, scheme string) { // Set the account concurrency to 1. This _should_ result in the // range root to become correct, and there should be no healing needed defer func(old int) { accountConcurrency = old }(accountConcurrency) @@ -1717,7 +1817,7 @@ func TestSyncAccountPerformance(t *testing.T) { }) } ) - nodeScheme, sourceAccountTrie, elems := makeAccountTrieNoStorage(100) + nodeScheme, sourceAccountTrie, elems := makeAccountTrieNoStorage(100, scheme) mkSource := func(name string) *testPeer { source := newTestPeer(name, t, term) @@ -1730,7 +1830,7 @@ func TestSyncAccountPerformance(t *testing.T) { if err := syncer.Sync(sourceAccountTrie.Hash(), cancel); err != nil { t.Fatalf("sync failed: %v", err) } - verifyTrie(syncer.db, sourceAccountTrie.Hash(), t) + verifyTrie(scheme, syncer.db, sourceAccountTrie.Hash(), t) // The trie root will always be requested, since it is added when the snap // sync cycle starts. When popping the queue, we do not look it up again. // Doing so would bring this number down to zero in this artificial testcase, @@ -1790,3 +1890,10 @@ func TestSlotEstimation(t *testing.T) { } } } + +func newDbConfig(scheme string) *trie.Config { + if scheme == rawdb.HashScheme { + return &trie.Config{} + } + return &trie.Config{PathDB: pathdb.Defaults} +} diff --git a/eth/state_accessor.go b/eth/state_accessor.go index 1b0ab0c545..24694df66c 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -24,6 +24,7 @@ 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/types" "github.com/ethereum/go-ethereum/core/vm" @@ -36,31 +37,11 @@ import ( // for releasing state. var noopReleaser = tracers.StateReleaseFunc(func() {}) -// StateAtBlock retrieves the state database associated with a certain block. -// If no state is locally available for the given block, a number of blocks -// are attempted to be reexecuted to generate the desired state. The optional -// base layer statedb can be provided which is regarded as the statedb of the -// parent block. -// -// An additional release function will be returned if the requested state is -// available. Release is expected to be invoked when the returned state is no longer needed. -// Its purpose is to prevent resource leaking. Though it can be noop in some cases. -// -// Parameters: -// - block: The block for which we want the state(state = block.Root) -// - reexec: The maximum number of blocks to reprocess trying to obtain the desired state -// - base: If the caller is tracing multiple blocks, the caller can provide the parent -// state continuously from the callsite. -// - readOnly: If true, then the live 'blockchain' state database is used. No mutation should -// be made from caller, e.g. perform Commit or other 'save-to-disk' changes. -// Otherwise, the trash generated by caller may be persisted permanently. -// - preferDisk: this arg can be used by the caller to signal that even though the 'base' is -// provided, it would be preferable to start from a fresh state, if we have it -// on disk. -func (eth *Ethereum) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (statedb *state.StateDB, release tracers.StateReleaseFunc, err error) { +func (eth *Ethereum) hashState(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (statedb *state.StateDB, release tracers.StateReleaseFunc, err error) { var ( current *types.Block database state.Database + triedb *trie.Database report = true origin = block.NumberU64() ) @@ -71,9 +52,9 @@ func (eth *Ethereum) StateAtBlock(ctx context.Context, block *types.Block, reexe // on top to prevent garbage collection and return a release // function to deref it. if statedb, err = eth.blockchain.StateAt(block.Root()); err == nil { - statedb.Database().TrieDB().Reference(block.Root(), common.Hash{}) + eth.blockchain.TrieDB().Reference(block.Root(), common.Hash{}) return statedb, func() { - statedb.Database().TrieDB().Dereference(block.Root()) + eth.blockchain.TrieDB().Dereference(block.Root()) }, nil } } @@ -84,14 +65,16 @@ func (eth *Ethereum) StateAtBlock(ctx context.Context, block *types.Block, reexe if preferDisk { // Create an ephemeral trie.Database for isolating the live one. Otherwise // the internal junks created by tracing will be persisted into the disk. - database = state.NewDatabaseWithConfig(eth.chainDb, &trie.Config{Cache: 16}) + // TODO(rjl493456442), clean cache is disabled to prevent memory leak, + // please re-enable it for better performance. + database = state.NewDatabaseWithConfig(eth.chainDb, trie.HashDefaults) if statedb, err = state.New(block.Root(), database, nil); err == nil { log.Info("Found disk backend for state trie", "root", block.Root(), "number", block.Number()) return statedb, noopReleaser, nil } } // The optional base statedb is given, mark the start point as parent block - statedb, database, report = base, base.Database(), false + statedb, database, triedb, report = base, base.Database(), base.Database().TrieDB(), false current = eth.blockchain.GetBlock(block.ParentHash(), block.NumberU64()-1) } else { // Otherwise, try to reexec blocks until we find a state or reach our limit @@ -99,7 +82,10 @@ func (eth *Ethereum) StateAtBlock(ctx context.Context, block *types.Block, reexe // Create an ephemeral trie.Database for isolating the live one. Otherwise // the internal junks created by tracing will be persisted into the disk. - database = state.NewDatabaseWithConfig(eth.chainDb, &trie.Config{Cache: 16}) + // TODO(rjl493456442), clean cache is disabled to prevent memory leak, + // please re-enable it for better performance. + triedb = trie.NewDatabase(eth.chainDb, trie.HashDefaults) + database = state.NewDatabaseWithNodeDB(eth.chainDb, triedb) // 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 @@ -164,7 +150,7 @@ func (eth *Ethereum) StateAtBlock(ctx context.Context, block *types.Block, reexe return nil, nil, fmt.Errorf("processing block %d failed: %v", current.NumberU64(), err) } // Finalize the state so any modifications are written to the trie - root, err := statedb.Commit(eth.blockchain.Config().IsEIP158(current.Number())) + root, err := statedb.Commit(current.NumberU64(), eth.blockchain.Config().IsEIP158(current.Number())) if err != nil { return nil, nil, fmt.Errorf("stateAtBlock commit failed, number %d root %v: %w", current.NumberU64(), current.Root().Hex(), err) @@ -175,17 +161,58 @@ func (eth *Ethereum) StateAtBlock(ctx context.Context, block *types.Block, reexe } // Hold the state reference and also drop the parent state // to prevent accumulating too many nodes in memory. - database.TrieDB().Reference(root, common.Hash{}) + triedb.Reference(root, common.Hash{}) if parent != (common.Hash{}) { - database.TrieDB().Dereference(parent) + triedb.Dereference(parent) } parent = root } if report { - nodes, imgs := database.TrieDB().Size() + _, nodes, imgs := triedb.Size() // all memory is contained within the nodes return in hashdb log.Info("Historical state regenerated", "block", current.NumberU64(), "elapsed", time.Since(start), "nodes", nodes, "preimages", imgs) } - return statedb, func() { database.TrieDB().Dereference(block.Root()) }, nil + return statedb, func() { triedb.Dereference(block.Root()) }, nil +} + +func (eth *Ethereum) pathState(block *types.Block) (*state.StateDB, func(), error) { + // Check if the requested state is available in the live chain. + statedb, err := eth.blockchain.StateAt(block.Root()) + if err == nil { + return statedb, noopReleaser, nil + } + // TODO historic state is not supported in path-based scheme. + // Fully archive node in pbss will be implemented by relying + // on state history, but needs more work on top. + return nil, nil, errors.New("historical state not available in path scheme yet") +} + +// stateAtBlock retrieves the state database associated with a certain block. +// If no state is locally available for the given block, a number of blocks +// are attempted to be reexecuted to generate the desired state. The optional +// base layer statedb can be provided which is regarded as the statedb of the +// parent block. +// +// An additional release function will be returned if the requested state is +// available. Release is expected to be invoked when the returned state is no +// longer needed. Its purpose is to prevent resource leaking. Though it can be +// noop in some cases. +// +// Parameters: +// - block: The block for which we want the state(state = block.Root) +// - reexec: The maximum number of blocks to reprocess trying to obtain the desired state +// - base: If the caller is tracing multiple blocks, the caller can provide the parent +// state continuously from the callsite. +// - readOnly: If true, then the live 'blockchain' state database is used. No mutation should +// be made from caller, e.g. perform Commit or other 'save-to-disk' changes. +// Otherwise, the trash generated by caller may be persisted permanently. +// - preferDisk: This arg can be used by the caller to signal that even though the 'base' is +// provided, it would be preferable to start from a fresh state, if we have it +// on disk. +func (eth *Ethereum) stateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (statedb *state.StateDB, release tracers.StateReleaseFunc, err error) { + if eth.blockchain.TrieDB().Scheme() == rawdb.HashScheme { + return eth.hashState(ctx, block, reexec, base, readOnly, preferDisk) + } + return eth.pathState(block) } // stateAtTransaction returns the execution environment of a certain transaction. @@ -201,7 +228,7 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, } // Lookup the statedb of parent block from the live database, // otherwise regenerate it on the flight. - statedb, release, err := eth.StateAtBlock(ctx, parent, reexec, nil, true, false) + statedb, release, err := eth.stateAtBlock(ctx, parent, reexec, nil, true, false) if err != nil { return nil, vm.BlockContext{}, nil, nil, err } diff --git a/eth/sync.go b/eth/sync.go index ace1071143..ba7a7427a5 100644 --- a/eth/sync.go +++ b/eth/sync.go @@ -23,7 +23,6 @@ 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/eth/downloader" "github.com/ethereum/go-ethereum/eth/protocols/eth" "github.com/ethereum/go-ethereum/log" @@ -36,27 +35,15 @@ const ( // syncTransactions starts sending all currently pending transactions to the given peer. func (h *handler) syncTransactions(p *eth.Peer) { - // Assemble the set of transaction to broadcast or announce to the remote - // peer. Fun fact, this is quite an expensive operation as it needs to sort - // the transactions if the sorting is not cached yet. However, with a random - // order, insertions could overflow the non-executable queues and get dropped. - // - // TODO(karalabe): Figure out if we could get away with random order somehow - var txs types.Transactions - pending := h.txpool.Pending(false) - for _, batch := range pending { - txs = append(txs, batch...) + var hashes []common.Hash + for _, batch := range h.txpool.Pending(false) { + for _, tx := range batch { + hashes = append(hashes, tx.Hash) + } } - if len(txs) == 0 { + if len(hashes) == 0 { return } - // The eth/65 protocol introduces proper transaction announcements, so instead - // of dripping transactions across multiple peers, just send the entire list as - // an announcement and let the remote side decide what they need (likely nothing). - hashes := make([]common.Hash, len(txs)) - for i, tx := range txs { - hashes[i] = tx.Hash() - } p.AsyncSendPooledTransactionHashes(hashes) } @@ -89,7 +76,7 @@ func newChainSyncer(handler *handler) *chainSyncer { // 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(peer *eth.Peer) bool { +func (cs *chainSyncer) handlePeerEvent() bool { select { case cs.peerEventCh <- struct{}{}: return true diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 1e55d8dcfe..6d0d6c8326 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -18,7 +18,6 @@ package tracers import ( "bufio" - "bytes" "context" "encoding/json" "errors" @@ -369,8 +368,8 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed // if the relevant state is available in disk. var preferDisk bool if statedb != nil { - s1, s2 := statedb.Database().TrieDB().Size() - preferDisk = s1+s2 > defaultTracechainMemLimit + s1, s2, s3 := statedb.Database().TrieDB().Size() + preferDisk = s1+s2+s3 > defaultTracechainMemLimit } statedb, release, err = api.backend.StateAtBlock(ctx, block, reexec, statedb, false, preferDisk) if err != nil { @@ -453,7 +452,7 @@ func (api *API) TraceBlockByHash(ctx context.Context, hash common.Hash, config * // and returns them as a JSON object. func (api *API) TraceBlock(ctx context.Context, blob hexutil.Bytes, config *TraceConfig) ([]*txTraceResult, error) { block := new(types.Block) - if err := rlp.Decode(bytes.NewReader(blob), block); err != nil { + if err := rlp.DecodeBytes(blob, block); err != nil { return nil, fmt.Errorf("could not decode block: %v", err) } return api.traceBlock(ctx, block, config) @@ -1022,6 +1021,10 @@ func overrideConfig(original *params.ChainConfig, override *params.ChainConfig) copy.PragueTime = timestamp canon = false } + if timestamp := override.VerkleTime; timestamp != nil { + copy.VerkleTime = timestamp + canon = false + } return copy, canon } diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index fdb02b1895..0f78af9a01 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -17,7 +17,6 @@ package tracers import ( - "bytes" "context" "crypto/ecdsa" "encoding/json" @@ -25,7 +24,6 @@ import ( "fmt" "math/big" "reflect" - "sort" "sync/atomic" "testing" "time" @@ -45,6 +43,7 @@ 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 ( @@ -785,19 +784,13 @@ type Account struct { addr common.Address } -type Accounts []Account - -func (a Accounts) Len() int { return len(a) } -func (a Accounts) Swap(i, j int) { a[i], a[j] = a[j], a[i] } -func (a Accounts) Less(i, j int) bool { return bytes.Compare(a[i].addr.Bytes(), a[j].addr.Bytes()) < 0 } - -func newAccounts(n int) (accounts Accounts) { +func newAccounts(n int) (accounts []Account) { for i := 0; i < n; i++ { key, _ := crypto.GenerateKey() addr := crypto.PubkeyToAddress(key.PublicKey) accounts = append(accounts, Account{key: key, addr: addr}) } - sort.Sort(accounts) + slices.SortFunc(accounts, func(a, b Account) int { return a.addr.Cmp(b.addr) }) return accounts } diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index bf1c31c08d..6df49a90c1 100644 --- a/eth/tracers/internal/tracetest/calltrace_test.go +++ b/eth/tracers/internal/tracetest/calltrace_test.go @@ -137,8 +137,10 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) { GasLimit: uint64(test.Context.GasLimit), BaseFee: test.Genesis.BaseFee, } - _, statedb = tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false) + triedb, _, statedb = tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false, rawdb.HashScheme) ) + triedb.Close() + tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig) if err != nil { t.Fatalf("failed to create call tracer: %v", err) @@ -237,7 +239,8 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) { Difficulty: (*big.Int)(test.Context.Difficulty), GasLimit: uint64(test.Context.GasLimit), } - _, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false) + triedb, _, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false, rawdb.HashScheme) + defer triedb.Close() b.ReportAllocs() b.ResetTimer() @@ -302,13 +305,13 @@ func TestInternals(t *testing.T) { byte(vm.CALL), }, tracer: mkTracer("callTracer", nil), - want: `{"from":"0x000000000000000000000000000000000000feed","gas":"0xc350","gasUsed":"0x54d8","to":"0x00000000000000000000000000000000deadbeef","input":"0x","calls":[{"from":"0x00000000000000000000000000000000deadbeef","gas":"0x6cbf","gasUsed":"0x0","to":"0x00000000000000000000000000000000000000ff","input":"0x","value":"0x0","type":"CALL"}],"value":"0x0","type":"CALL"}`, + 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"}`, }, { name: "Stack depletion in LOG0", code: []byte{byte(vm.LOG3)}, tracer: mkTracer("callTracer", json.RawMessage(`{ "withLog": true }`)), - want: `{"from":"0x000000000000000000000000000000000000feed","gas":"0xc350","gasUsed":"0xc350","to":"0x00000000000000000000000000000000deadbeef","input":"0x","error":"stack underflow (0 \u003c=\u003e 5)","value":"0x0","type":"CALL"}`, + want: `{"from":"0x000000000000000000000000000000000000feed","gas":"0x13880","gasUsed":"0x13880","to":"0x00000000000000000000000000000000deadbeef","input":"0x","error":"stack underflow (0 \u003c=\u003e 5)","value":"0x0","type":"CALL"}`, }, { name: "Mem expansion in LOG0", @@ -321,11 +324,11 @@ func TestInternals(t *testing.T) { byte(vm.LOG0), }, tracer: mkTracer("callTracer", json.RawMessage(`{ "withLog": true }`)), - want: `{"from":"0x000000000000000000000000000000000000feed","gas":"0xc350","gasUsed":"0x5b9e","to":"0x00000000000000000000000000000000deadbeef","input":"0x","logs":[{"address":"0x00000000000000000000000000000000deadbeef","topics":[],"data":"0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}],"value":"0x0","type":"CALL"}`, + want: `{"from":"0x000000000000000000000000000000000000feed","gas":"0x13880","gasUsed":"0x5b9e","to":"0x00000000000000000000000000000000deadbeef","input":"0x","logs":[{"address":"0x00000000000000000000000000000000deadbeef","topics":[],"data":"0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}],"value":"0x0","type":"CALL"}`, }, { // Leads to OOM on the prestate tracer - name: "Prestate-tracer - mem expansion in CREATE2", + name: "Prestate-tracer - CREATE2 OOM", code: []byte{ byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x0, @@ -339,41 +342,64 @@ func TestInternals(t *testing.T) { byte(vm.PUSH1), 0x0, byte(vm.LOG0), }, - tracer: mkTracer("prestateTracer", json.RawMessage(`{ "withLog": true }`)), - want: `{"0x0000000000000000000000000000000000000000":{"balance":"0x0"},"0x000000000000000000000000000000000000feed":{"balance":"0x1c6bf52640350"},"0x00000000000000000000000000000000deadbeef":{"balance":"0x0","code":"0x6001600052600164ffffffffff60016000f560ff6000a0"}}`, + tracer: mkTracer("prestateTracer", nil), + want: `{"0x0000000000000000000000000000000000000000":{"balance":"0x0"},"0x000000000000000000000000000000000000feed":{"balance":"0x1c6bf52647880"},"0x00000000000000000000000000000000deadbeef":{"balance":"0x0","code":"0x6001600052600164ffffffffff60016000f560ff6000a0"}}`, + }, + { + // CREATE2 which requires padding memory by prestate tracer + name: "Prestate-tracer - CREATE2 Memory padding", + code: []byte{ + byte(vm.PUSH1), 0x1, + byte(vm.PUSH1), 0x0, + byte(vm.MSTORE), + byte(vm.PUSH1), 0x1, + byte(vm.PUSH1), 0xff, + byte(vm.PUSH1), 0x1, + byte(vm.PUSH1), 0x0, + byte(vm.CREATE2), + byte(vm.PUSH1), 0xff, + byte(vm.PUSH1), 0x0, + byte(vm.LOG0), + }, + tracer: mkTracer("prestateTracer", nil), + want: `{"0x0000000000000000000000000000000000000000":{"balance":"0x0"},"0x000000000000000000000000000000000000feed":{"balance":"0x1c6bf52647880"},"0x00000000000000000000000000000000deadbeef":{"balance":"0x0","code":"0x6001600052600160ff60016000f560ff6000a0"},"0x91ff9a805d36f54e3e272e230f3e3f5c1b330804":{"balance":"0x0"}}`, }, } { - _, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), - core.GenesisAlloc{ - to: core.GenesisAccount{ - Code: tc.code, - }, - origin: core.GenesisAccount{ - Balance: big.NewInt(500000000000000), - }, - }, false) - evm := vm.NewEVM(context, txContext, statedb, params.MainnetChainConfig, vm.Config{Tracer: tc.tracer}) - msg := &core.Message{ - To: &to, - From: origin, - Value: big.NewInt(0), - GasLimit: 50000, - GasPrice: big.NewInt(0), - GasFeeCap: big.NewInt(0), - GasTipCap: big.NewInt(0), - SkipAccountChecks: false, - } - st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(msg.GasLimit)) - if _, err := st.TransitionDb(); err != nil { - t.Fatalf("test %v: failed to execute transaction: %v", tc.name, err) - } - // Retrieve the trace result and compare against the expected - res, err := tc.tracer.GetResult() - if err != nil { - t.Fatalf("test %v: failed to retrieve trace result: %v", tc.name, err) - } - if string(res) != tc.want { - t.Fatalf("test %v: trace mismatch\n have: %v\n want: %v\n", tc.name, string(res), tc.want) - } + t.Run(tc.name, func(t *testing.T) { + triedb, _, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), + core.GenesisAlloc{ + to: core.GenesisAccount{ + Code: tc.code, + }, + origin: core.GenesisAccount{ + Balance: big.NewInt(500000000000000), + }, + }, false, rawdb.HashScheme) + defer triedb.Close() + + evm := vm.NewEVM(context, txContext, 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, + } + st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(msg.GasLimit)) + if _, err := st.TransitionDb(); err != nil { + t.Fatalf("test %v: failed to execute transaction: %v", tc.name, err) + } + // Retrieve the trace result and compare against the expected + res, err := tc.tracer.GetResult() + if err != nil { + t.Fatalf("test %v: failed to retrieve trace result: %v", tc.name, err) + } + if string(res) != tc.want { + t.Errorf("test %v: trace mismatch\n have: %v\n want: %v\n", tc.name, string(res), tc.want) + } + }) } } diff --git a/eth/tracers/internal/tracetest/flat_calltrace_test.go b/eth/tracers/internal/tracetest/flat_calltrace_test.go index 85e95401a2..423167b13c 100644 --- a/eth/tracers/internal/tracetest/flat_calltrace_test.go +++ b/eth/tracers/internal/tracetest/flat_calltrace_test.go @@ -100,7 +100,8 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string Difficulty: (*big.Int)(test.Context.Difficulty), GasLimit: uint64(test.Context.GasLimit), } - _, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false) + triedb, _, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false, rawdb.HashScheme) + defer triedb.Close() // Create the tracer, the EVM environment and run it tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig) diff --git a/eth/tracers/internal/tracetest/prestate_test.go b/eth/tracers/internal/tracetest/prestate_test.go index 991da10b3a..b4fa5b6272 100644 --- a/eth/tracers/internal/tracetest/prestate_test.go +++ b/eth/tracers/internal/tracetest/prestate_test.go @@ -108,8 +108,10 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) { GasLimit: uint64(test.Context.GasLimit), BaseFee: test.Genesis.BaseFee, } - _, statedb = tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false) + triedb, _, statedb = tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false, rawdb.HashScheme) ) + defer triedb.Close() + 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_flat/simple_onlytop.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/simple_onlytop.json new file mode 100644 index 0000000000..5fbdf55d22 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/simple_onlytop.json @@ -0,0 +1,100 @@ +{ + "context": { + "difficulty": "3502894804", + "gasLimit": "4722976", + "miner": "0x1585936b53834b021f68cc13eeefdec2efc8e724", + "number": "2289806", + "timestamp": "1513601314" + }, + "genesis": { + "alloc": { + "0x0024f658a46fbb89d8ac105e98d7ac7cbbaf27c5": { + "balance": "0x0", + "code": "0x", + "nonce": "22", + "storage": {} + }, + "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe": { + "balance": "0x4d87094125a369d9bd5", + "code": "0x606060405236156100935763ffffffff60e060020a60003504166311ee8382811461009c57806313af4035146100be5780631f5e8f4c146100ee57806324daddc5146101125780634921a91a1461013b57806363e4bff414610157578063764978f91461017f578063893d20e8146101a1578063ba40aaa1146101cd578063cebc9a82146101f4578063e177246e14610216575b61009a5b5b565b005b34156100a457fe5b6100ac61023d565b60408051918252519081900360200190f35b34156100c657fe5b6100da600160a060020a0360043516610244565b604080519115158252519081900360200190f35b34156100f657fe5b6100da610307565b604080519115158252519081900360200190f35b341561011a57fe5b6100da6004351515610318565b604080519115158252519081900360200190f35b6100da6103d6565b604080519115158252519081900360200190f35b6100da600160a060020a0360043516610420565b604080519115158252519081900360200190f35b341561018757fe5b6100ac61046c565b60408051918252519081900360200190f35b34156101a957fe5b6101b1610473565b60408051600160a060020a039092168252519081900360200190f35b34156101d557fe5b6100da600435610483565b604080519115158252519081900360200190f35b34156101fc57fe5b6100ac61050d565b60408051918252519081900360200190f35b341561021e57fe5b6100da600435610514565b604080519115158252519081900360200190f35b6003545b90565b60006000610250610473565b600160a060020a031633600160a060020a03161415156102705760006000fd5b600160a060020a03831615156102865760006000fd5b50600054600160a060020a0390811690831681146102fb57604051600160a060020a0380851691908316907ffcf23a92150d56e85e3a3d33b357493246e55783095eb6a733eb8439ffc752c890600090a360008054600160a060020a031916600160a060020a03851617905560019150610300565b600091505b5b50919050565b60005460a060020a900460ff165b90565b60006000610324610473565b600160a060020a031633600160a060020a03161415156103445760006000fd5b5060005460a060020a900460ff16801515831515146102fb576000546040805160a060020a90920460ff1615158252841515602083015280517fe6cd46a119083b86efc6884b970bfa30c1708f53ba57b86716f15b2f4551a9539281900390910190a16000805460a060020a60ff02191660a060020a8515150217905560019150610300565b600091505b5b50919050565b60006103e0610307565b801561040557506103ef610473565b600160a060020a031633600160a060020a031614155b156104105760006000fd5b610419336105a0565b90505b5b90565b600061042a610307565b801561044f5750610439610473565b600160a060020a031633600160a060020a031614155b1561045a5760006000fd5b610463826105a0565b90505b5b919050565b6001545b90565b600054600160a060020a03165b90565b6000600061048f610473565b600160a060020a031633600160a060020a03161415156104af5760006000fd5b506001548281146102fb57604080518281526020810185905281517f79a3746dde45672c9e8ab3644b8bb9c399a103da2dc94b56ba09777330a83509929181900390910190a160018381559150610300565b600091505b5b50919050565b6002545b90565b60006000610520610473565b600160a060020a031633600160a060020a03161415156105405760006000fd5b506002548281146102fb57604080518281526020810185905281517ff6991a728965fedd6e927fdf16bdad42d8995970b4b31b8a2bf88767516e2494929181900390910190a1600283905560019150610300565b600091505b5b50919050565b60006000426105ad61023d565b116102fb576105c46105bd61050d565b4201610652565b6105cc61046c565b604051909150600160a060020a038416908290600081818185876187965a03f1925050501561063d57604080518281529051600160a060020a038516917f9bca65ce52fdef8a470977b51f247a2295123a4807dfa9e502edf0d30722da3b919081900360200190a260019150610300565b6102fb42610652565b5b600091505b50919050565b60038190555b505600a165627a7a72305820f3c973c8b7ed1f62000b6701bd5b708469e19d0f1d73fde378a56c07fd0b19090029", + "nonce": "1", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000001b436ba50d378d4bbc8660d312a13df6af6e89dfb", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x00000000000000000000000000000000000000000000000006f05b59d3b20000", + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x000000000000000000000000000000000000000000000000000000000000003c", + "0x0000000000000000000000000000000000000000000000000000000000000003": "0x000000000000000000000000000000000000000000000000000000005a37b834" + } + }, + "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb": { + "balance": "0x1780d77678137ac1b775", + "code": "0x", + "nonce": "29072", + "storage": {} + } + }, + "config": { + "byzantiumBlock": 1700000, + "chainId": 3, + "daoForkSupport": true, + "eip150Block": 0, + "eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d", + "eip155Block": 10, + "eip158Block": 10, + "ethash": {}, + "homesteadBlock": 0 + }, + "difficulty": "3509749784", + "extraData": "0x4554482e45544846414e532e4f52472d4641313738394444", + "gasLimit": "4727564", + "hash": "0x609948ac3bd3c00b7736b933248891d6c901ee28f066241bddb28f4e00a9f440", + "miner": "0xbbf5029fd710d227630c8b7d338051b8e76d50b3", + "mixHash": "0xb131e4507c93c7377de00e7c271bf409ec7492767142ff0f45c882f8068c2ada", + "nonce": "0x4eb12e19c16d43da", + "number": "2289805", + "stateRoot": "0xc7f10f352bff82fac3c2999d3085093d12652e19c7fd32591de49dc5d91b4f1f", + "timestamp": "1513601261", + "totalDifficulty": "7143276353481064" + }, + "input": "0xf88b8271908506fc23ac0083015f90943b873a919aa0512d5a0f09e6dcceaa4a6727fafe80a463e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c52aa0bdce0b59e8761854e857fe64015f06dd08a4fbb7624f6094893a79a72e6ad6bea01d9dde033cff7bb235a3163f348a6d7ab8d6b52bc0963a95b91612e40ca766a4", + "tracerConfig": { + "onlyTopCall": true + }, + "result": [ + { + "action": { + "callType": "call", + "from": "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb", + "gas": "0x15f90", + "input": "0x63e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c5", + "to": "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe", + "value": "0x0" + }, + "blockNumber": 2289806, + "result": { + "gasUsed": "0x9751", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001" + }, + "subtraces": 1, + "traceAddress": [], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe", + "gas": "0x6d05", + "input": "0x", + "to": "0x0024f658a46fbb89d8ac105e98d7ac7cbbaf27c5", + "value": "0x6f05b59d3b20000" + }, + "blockNumber": 0, + "result": { + "gasUsed": "0x0", + "output": "0x" + }, + "subtraces": 0, + "traceAddress": [0], + "type": "call" + } + ] +} diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index 2a2789e93d..d22d140988 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -86,10 +86,10 @@ func fromBuf(vm *goja.Runtime, bufType goja.Value, buf goja.Value, allowString b if !obj.Get("constructor").SameAs(bufType) { break } - b := obj.Get("buffer").Export().(goja.ArrayBuffer).Bytes() + b := obj.Export().([]byte) return b, nil } - return nil, fmt.Errorf("invalid buffer type") + return nil, errors.New("invalid buffer type") } // jsTracer is an implementation of the Tracer interface which evaluates @@ -236,7 +236,12 @@ func (t *jsTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Addr t.ctx["to"] = t.vm.ToValue(to.Bytes()) t.ctx["input"] = t.vm.ToValue(input) t.ctx["gas"] = t.vm.ToValue(t.gasLimit) - t.ctx["gasPrice"] = t.vm.ToValue(env.TxContext.GasPrice) + gasPriceBig, err := t.toBig(t.vm, env.TxContext.GasPrice.String()) + if err != nil { + t.err = err + return + } + t.ctx["gasPrice"] = gasPriceBig valueBig, err := t.toBig(t.vm, value.String()) if err != nil { t.err = err diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index c7f171c5bd..4c9b910a27 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -418,6 +418,7 @@ type StructLogRes struct { Depth int `json:"depth"` Error string `json:"error,omitempty"` Stack *[]string `json:"stack,omitempty"` + ReturnData string `json:"returnData,omitempty"` Memory *[]string `json:"memory,omitempty"` Storage *map[string]string `json:"storage,omitempty"` RefundCounter uint64 `json:"refund,omitempty"` @@ -443,6 +444,9 @@ func formatLogs(logs []StructLog) []StructLogRes { } formatted[index].Stack = &stack } + if trace.ReturnData != nil && len(trace.ReturnData) > 0 { + formatted[index].ReturnData = hexutil.Bytes(trace.ReturnData).String() + } if trace.Memory != nil { memory := make([]string, 0, (len(trace.Memory)+31)/32) for i := 0; i+32 <= len(trace.Memory); i += 32 { diff --git a/eth/tracers/logger/logger_test.go b/eth/tracers/logger/logger_test.go index bde43e5ff7..3192a15cba 100644 --- a/eth/tracers/logger/logger_test.go +++ b/eth/tracers/logger/logger_test.go @@ -18,7 +18,7 @@ package logger import ( "encoding/json" - "fmt" + "errors" "math/big" "testing" @@ -85,7 +85,7 @@ func TestStructLogMarshalingOmitEmpty(t *testing.T) { }{ {"empty err and no fields", &StructLog{}, `{"pc":0,"op":0,"gas":"0x0","gasCost":"0x0","memSize":0,"stack":null,"depth":0,"refund":0,"opName":"STOP"}`}, - {"with err", &StructLog{Err: fmt.Errorf("this failed")}, + {"with err", &StructLog{Err: errors.New("this failed")}, `{"pc":0,"op":0,"gas":"0x0","gasCost":"0x0","memSize":0,"stack":null,"depth":0,"refund":0,"opName":"STOP","error":"this failed"}`}, {"with mem", &StructLog{Memory: make([]byte, 2), MemorySize: 2}, `{"pc":0,"op":0,"gas":"0x0","gasCost":"0x0","memory":"0x0000","memSize":2,"stack":null,"depth":0,"refund":0,"opName":"STOP"}`}, diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index 4ac03e512f..34cf027aca 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -27,6 +27,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "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 @@ -183,6 +184,7 @@ func (t *callTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, sco 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 } diff --git a/eth/tracers/native/call_flat.go b/eth/tracers/native/call_flat.go index 5da6040506..266ab99001 100644 --- a/eth/tracers/native/call_flat.go +++ b/eth/tracers/native/call_flat.go @@ -129,7 +129,9 @@ func newFlatCallTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.Trace } } - tracer, err := tracers.DefaultDirectory.New("callTracer", ctx, cfg) + // 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) if err != nil { return nil, err } @@ -246,7 +248,7 @@ func flatFromNested(input *callFrame, traceAddress []int, convertErrs bool, ctx case vm.CREATE, vm.CREATE2: frame = newFlatCreate(input) case vm.SELFDESTRUCT: - frame = newFlatSuicide(input) + frame = newFlatSelfdestruct(input) case vm.CALL, vm.STATICCALL, vm.CALLCODE, vm.DELEGATECALL: frame = newFlatCall(input) default: @@ -328,7 +330,7 @@ func newFlatCall(input *callFrame) *flatCallFrame { } } -func newFlatSuicide(input *callFrame) *flatCallFrame { +func newFlatSelfdestruct(input *callFrame) *flatCallFrame { return &flatCallFrame{ Type: "suicide", Action: flatCallAction{ diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index b71d5d6215..82451c40a6 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -27,6 +27,7 @@ import ( "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/log" ) //go:generate go run github.com/fjl/gencodec -type account -field-override accountMarshaling -out gen_account_json.go @@ -165,7 +166,11 @@ 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 := scope.Memory.GetCopy(int64(offset.Uint64()), int64(size.Uint64())) + init, err := tracers.GetMemoryCopyPadded(scope.Memory, 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 + } inithash := crypto.Keccak256(init) salt := stackData[stackLen-4] addr := crypto.CreateAddress2(caller, salt.Bytes32(), inithash) diff --git a/eth/tracers/tracers.go b/eth/tracers/tracers.go index 023f73ef37..7b43b7cf83 100644 --- a/eth/tracers/tracers.go +++ b/eth/tracers/tracers.go @@ -19,6 +19,7 @@ package tracers import ( "encoding/json" + "errors" "fmt" "math/big" @@ -105,7 +106,7 @@ const ( // 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, fmt.Errorf("offset or size must not be negative") + 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 diff --git a/eth/tracers/tracers_test.go b/eth/tracers/tracers_test.go index 759e3a4dd3..b4989ec984 100644 --- a/eth/tracers/tracers_test.go +++ b/eth/tracers/tracers_test.go @@ -79,7 +79,9 @@ func BenchmarkTransactionTrace(b *testing.B) { Code: []byte{}, Balance: big.NewInt(500000000000000), } - _, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), alloc, false) + triedb, _, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), alloc, false, rawdb.HashScheme) + defer triedb.Close() + // Create the tracer, the EVM environment and run it tracer := logger.NewStructLogger(&logger.Config{ Debug: false, diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index 09d3f37d1e..a21d8ff67a 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -108,6 +108,16 @@ func (ec *Client) PeerCount(ctx context.Context) (uint64, error) { return uint64(result), err } +// BlockReceipts returns the receipts of a given block number or hash +func (ec *Client) BlockReceipts(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) ([]*types.Receipt, error) { + var r []*types.Receipt + err := ec.c.CallContext(ctx, &r, "eth_getBlockReceipts", blockNrOrHash) + if err == nil && r == nil { + return nil, ethereum.NotFound + } + return r, err +} + type rpcBlock struct { Hash common.Hash `json:"hash"` Transactions []rpcTransaction `json:"transactions"` @@ -138,16 +148,16 @@ func (ec *Client) getBlock(ctx context.Context, method string, args ...interface } // Quick-verify transaction and uncle lists. This mostly helps with debugging the server. if head.UncleHash == types.EmptyUncleHash && len(body.UncleHashes) > 0 { - return nil, fmt.Errorf("server returned non-empty uncle list but block header indicates no uncles") + return nil, errors.New("server returned non-empty uncle list but block header indicates no uncles") } if head.UncleHash != types.EmptyUncleHash && len(body.UncleHashes) == 0 { - return nil, fmt.Errorf("server returned empty uncle list but block header indicates uncles") + return nil, errors.New("server returned empty uncle list but block header indicates uncles") } if head.TxHash == types.EmptyTxsHash && len(body.Transactions) > 0 { - return nil, fmt.Errorf("server returned non-empty transaction list but block header indicates no transactions") + return nil, errors.New("server returned non-empty transaction list but block header indicates no transactions") } if head.TxHash != types.EmptyTxsHash && len(body.Transactions) == 0 { - return nil, fmt.Errorf("server returned empty transaction list but block header indicates transactions") + return nil, errors.New("server returned empty transaction list but block header indicates transactions") } // Load uncles because they are not included in the block response. var uncles []*types.Header @@ -232,7 +242,7 @@ func (ec *Client) TransactionByHash(ctx context.Context, hash common.Hash) (tx * } else if json == nil { return nil, false, ethereum.NotFound } else if _, r, _ := json.tx.RawSignatureValues(); r == nil { - return nil, false, fmt.Errorf("server returned transaction without signature") + return nil, false, errors.New("server returned transaction without signature") } if json.From != nil && json.BlockHash != nil { setSenderFromServer(json.tx, *json.From, *json.BlockHash) @@ -284,7 +294,7 @@ func (ec *Client) TransactionInBlock(ctx context.Context, blockHash common.Hash, if json == nil { return nil, ethereum.NotFound } else if _, r, _ := json.tx.RawSignatureValues(); r == nil { - return nil, fmt.Errorf("server returned transaction without signature") + return nil, errors.New("server returned transaction without signature") } if json.From != nil && json.BlockHash != nil { setSenderFromServer(json.tx, *json.From, *json.BlockHash) @@ -421,7 +431,7 @@ func toFilterArg(q ethereum.FilterQuery) (interface{}, error) { if q.BlockHash != nil { arg["blockHash"] = *q.BlockHash if q.FromBlock != nil || q.ToBlock != nil { - return nil, fmt.Errorf("cannot specify both BlockHash and FromBlock/ToBlock") + return nil, errors.New("cannot specify both BlockHash and FromBlock/ToBlock") } } else { if q.FromBlock == nil { @@ -592,19 +602,15 @@ func toBlockNumArg(number *big.Int) string { if number == nil { return "latest" } - pending := big.NewInt(-1) - if number.Cmp(pending) == 0 { - return "pending" + if number.Sign() >= 0 { + return hexutil.EncodeBig(number) } - finalized := big.NewInt(int64(rpc.FinalizedBlockNumber)) - if number.Cmp(finalized) == 0 { - return "finalized" + // It's negative. + if number.IsInt64() { + return rpc.BlockNumber(number.Int64()).String() } - safe := big.NewInt(int64(rpc.SafeBlockNumber)) - if number.Cmp(safe) == 0 { - return "safe" - } - return hexutil.EncodeBig(number) + // It's negative and large, which is invalid. + return fmt.Sprintf("", number) } func toCallArg(msg ethereum.CallMsg) interface{} { @@ -613,7 +619,7 @@ func toCallArg(msg ethereum.CallMsg) interface{} { "to": msg.To, } if len(msg.Data) > 0 { - arg["data"] = hexutil.Bytes(msg.Data) + arg["input"] = hexutil.Bytes(msg.Data) } if msg.Value != nil { arg["value"] = (*hexutil.Big)(msg.Value) diff --git a/ethclient/ethclient_test.go b/ethclient/ethclient_test.go index cd619862c7..d2f3710936 100644 --- a/ethclient/ethclient_test.go +++ b/ethclient/ethclient_test.go @@ -20,7 +20,6 @@ import ( "bytes" "context" "errors" - "fmt" "math/big" "reflect" "testing" @@ -55,7 +54,7 @@ var ( ) func TestToFilterArg(t *testing.T) { - blockHashErr := fmt.Errorf("cannot specify both BlockHash and FromBlock/ToBlock") + blockHashErr := errors.New("cannot specify both BlockHash and FromBlock/ToBlock") addresses := []common.Address{ common.HexToAddress("0xD36722ADeC3EdCB29c8e7b5a47f352D701393462"), } @@ -251,7 +250,7 @@ func generateTestChain() []*types.Block { func TestEthClient(t *testing.T) { backend, chain := newTestBackend(t) - client, _ := backend.Attach() + client := backend.Attach() defer backend.Close() defer client.Close() diff --git a/ethclient/gethclient/gethclient.go b/ethclient/gethclient/gethclient.go index 718cdfea42..e2c0ef3ed0 100644 --- a/ethclient/gethclient/gethclient.go +++ b/ethclient/gethclient/gethclient.go @@ -20,6 +20,7 @@ package gethclient import ( "context" "encoding/json" + "fmt" "math/big" "runtime" "runtime/debug" @@ -207,19 +208,15 @@ func toBlockNumArg(number *big.Int) string { if number == nil { return "latest" } - pending := big.NewInt(-1) - if number.Cmp(pending) == 0 { - return "pending" + if number.Sign() >= 0 { + return hexutil.EncodeBig(number) } - finalized := big.NewInt(int64(rpc.FinalizedBlockNumber)) - if number.Cmp(finalized) == 0 { - return "finalized" + // It's negative. + if number.IsInt64() { + return rpc.BlockNumber(number.Int64()).String() } - safe := big.NewInt(int64(rpc.SafeBlockNumber)) - if number.Cmp(safe) == 0 { - return "safe" - } - return hexutil.EncodeBig(number) + // It's negative and large, which is invalid. + return fmt.Sprintf("", number) } func toCallArg(msg ethereum.CallMsg) interface{} { @@ -228,7 +225,7 @@ func toCallArg(msg ethereum.CallMsg) interface{} { "to": msg.To, } if len(msg.Data) > 0 { - arg["data"] = hexutil.Bytes(msg.Data) + arg["input"] = hexutil.Bytes(msg.Data) } if msg.Value != nil { arg["value"] = (*hexutil.Big)(msg.Value) diff --git a/ethclient/gethclient/gethclient_test.go b/ethclient/gethclient/gethclient_test.go index 296d328484..5a0f4d2534 100644 --- a/ethclient/gethclient/gethclient_test.go +++ b/ethclient/gethclient/gethclient_test.go @@ -94,10 +94,7 @@ func generateTestChain() (*core.Genesis, []*types.Block) { func TestGethClient(t *testing.T) { backend, _ := newTestBackend(t) - client, err := backend.Attach() - if err != nil { - t.Fatal(err) - } + client := backend.Attach() defer backend.Close() defer client.Close() @@ -108,6 +105,9 @@ func TestGethClient(t *testing.T) { { "TestGetProof", func(t *testing.T) { testGetProof(t, client) }, + }, { + "TestGetProofCanonicalizeKeys", + func(t *testing.T) { testGetProofCanonicalizeKeys(t, client) }, }, { "TestGCStats", func(t *testing.T) { testGCStats(t, client) }, @@ -221,6 +221,7 @@ func testGetProof(t *testing.T, client *rpc.Client) { if result.Balance.Cmp(balance) != 0 { t.Fatalf("invalid balance, want: %v got: %v", balance, result.Balance) } + // test storage if len(result.StorageProof) != 1 { t.Fatalf("invalid storage proof, want 1 proof, got %v proof(s)", len(result.StorageProof)) @@ -231,7 +232,37 @@ func testGetProof(t *testing.T, client *rpc.Client) { t.Fatalf("invalid storage proof value, want: %v, got: %v", slotValue, proof.Value.Bytes()) } if proof.Key != testSlot.String() { - t.Fatalf("invalid storage proof key, want: %v, got: %v", testSlot.String(), proof.Key) + t.Fatalf("invalid storage proof key, want: %q, got: %q", testSlot.String(), proof.Key) + } +} + +func testGetProofCanonicalizeKeys(t *testing.T, client *rpc.Client) { + ec := New(client) + + // Tests with non-canon input for storage keys. + // Here we check that the storage key is canonicalized. + result, err := ec.GetProof(context.Background(), testAddr, []string{"0x0dEadbeef"}, nil) + if err != nil { + t.Fatal(err) + } + if result.StorageProof[0].Key != "0xdeadbeef" { + t.Fatalf("wrong storage key encoding in proof: %q", result.StorageProof[0].Key) + } + if result, err = ec.GetProof(context.Background(), testAddr, []string{"0x000deadbeef"}, nil); err != nil { + t.Fatal(err) + } + if result.StorageProof[0].Key != "0xdeadbeef" { + t.Fatalf("wrong storage key encoding in proof: %q", result.StorageProof[0].Key) + } + + // If the requested storage key is 32 bytes long, it will be returned as is. + hashSizedKey := "0x00000000000000000000000000000000000000000000000000000000deadbeef" + result, err = ec.GetProof(context.Background(), testAddr, []string{hashSizedKey}, nil) + if err != nil { + t.Fatal(err) + } + if result.StorageProof[0].Key != hashSizedKey { + t.Fatalf("wrong storage key encoding in proof: %q", result.StorageProof[0].Key) } } @@ -368,17 +399,17 @@ func testCallContract(t *testing.T, client *rpc.Client) { func TestOverrideAccountMarshal(t *testing.T) { om := map[common.Address]OverrideAccount{ - common.Address{0x11}: OverrideAccount{ + {0x11}: { // Zero-valued nonce is not overriddden, but simply dropped by the encoder. Nonce: 0, }, - common.Address{0xaa}: OverrideAccount{ + {0xaa}: { Nonce: 5, }, - common.Address{0xbb}: OverrideAccount{ + {0xbb}: { Code: []byte{1}, }, - common.Address{0xcc}: OverrideAccount{ + {0xcc}: { // 'code', 'balance', 'state' should be set when input is // a non-nil but empty value. Code: []byte{}, diff --git a/ethdb/database.go b/ethdb/database.go index 361218f247..4d4817daf2 100644 --- a/ethdb/database.go +++ b/ethdb/database.go @@ -79,9 +79,10 @@ type AncientReaderOp interface { // AncientRange retrieves multiple items in sequence, starting from the index 'start'. // It will return - // - at most 'count' items, - // - at least 1 item (even if exceeding the maxBytes), but will otherwise - // return as many items as fit into maxBytes. + // - 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 AncientRange(kind string, start, count, maxBytes uint64) ([][]byte, error) // Ancients returns the ancient item numbers in the ancient store. @@ -113,14 +114,14 @@ type AncientWriter interface { // TruncateHead discards all but the first n ancient data from the ancient store. // After the truncation, the latest item can be accessed it item_n-1(start from 0). - TruncateHead(n uint64) error + TruncateHead(n uint64) (uint64, error) // TruncateTail discards the first n ancient data from the ancient store. The already // deleted items are ignored. After the truncation, the earliest item can be accessed // is item_n(start from 0). The deleted items may not be removed from the ancient store // immediately, but only when the accumulated deleted data reach the threshold then // will be removed all together. - TruncateTail(n uint64) error + TruncateTail(n uint64) (uint64, error) // Sync flushes all in-memory ancient store data to disk. Sync() error diff --git a/ethdb/dbtest/testsuite.go b/ethdb/dbtest/testsuite.go index e455215cb0..0d3d5f5aa6 100644 --- a/ethdb/dbtest/testsuite.go +++ b/ethdb/dbtest/testsuite.go @@ -24,6 +24,7 @@ import ( "testing" "github.com/ethereum/go-ethereum/ethdb" + "golang.org/x/exp/slices" ) // TestDatabaseSuite runs a suite of tests against a KeyValueStore database @@ -376,6 +377,32 @@ func TestDatabaseSuite(t *testing.T, New func() ethdb.KeyValueStore) { } } }) + + t.Run("OperatonsAfterClose", func(t *testing.T) { + db := New() + db.Put([]byte("key"), []byte("value")) + db.Close() + if _, err := db.Get([]byte("key")); err == nil { + t.Fatalf("expected error on Get after Close") + } + if _, err := db.Has([]byte("key")); err == nil { + t.Fatalf("expected error on Get after Close") + } + if err := db.Put([]byte("key2"), []byte("value2")); err == nil { + t.Fatalf("expected error on Put after Close") + } + if err := db.Delete([]byte("key")); err == nil { + t.Fatalf("expected error on Delete after Close") + } + + b := db.NewBatch() + if err := b.Put([]byte("batchkey"), []byte("batchval")); err != nil { + t.Fatalf("expected no error on batch.Put after Close, got %v", err) + } + if err := b.Write(); err == nil { + t.Fatalf("expected error on batch.Write after Close") + } + }) } // BenchDatabaseSuite runs a suite of benchmarks against a KeyValueStore database @@ -500,7 +527,7 @@ func makeDataset(size, ksize, vsize int, order bool) ([][]byte, [][]byte) { vals = append(vals, randBytes(vsize)) } if order { - sort.Slice(keys, func(i, j int) bool { return bytes.Compare(keys[i], keys[j]) < 0 }) + slices.SortFunc(keys, func(a, b []byte) int { return bytes.Compare(a, b) }) } return keys, vals } diff --git a/ethdb/leveldb/leveldb.go b/ethdb/leveldb/leveldb.go index ce13659d9d..c0e0eb250a 100644 --- a/ethdb/leveldb/leveldb.go +++ b/ethdb/leveldb/leveldb.go @@ -22,8 +22,6 @@ package leveldb import ( "fmt" - "strconv" - "strings" "sync" "time" @@ -77,6 +75,8 @@ type Database struct { seekCompGauge metrics.Gauge // Gauge for tracking the number of table compaction caused by read opt manualMemAllocGauge metrics.Gauge // Gauge to track the amount of memory that has been manually allocated (not a part of runtime/GC) + levelsGauge []metrics.Gauge // Gauge for tracking the number of tables in levels + quitLock sync.Mutex // Mutex protecting the quit channel access quitChan chan chan error // Quit channel to stop the metrics collection before closing the database @@ -147,7 +147,7 @@ func NewCustom(file string, namespace string, customize func(options *opt.Option ldb.manualMemAllocGauge = metrics.NewRegisteredGauge(namespace+"memory/manualalloc", nil) // Start up the metrics gathering and return - go ldb.meter(metricsGatheringInterval) + go ldb.meter(metricsGatheringInterval, namespace) return ldb, nil } @@ -266,122 +266,63 @@ func (db *Database) Path() string { // meter periodically retrieves internal leveldb counters and reports them to // the metrics subsystem. -// -// This is how a LevelDB stats table looks like (currently): -// -// Compactions -// Level | Tables | Size(MB) | Time(sec) | Read(MB) | Write(MB) -// -------+------------+---------------+---------------+---------------+--------------- -// 0 | 0 | 0.00000 | 1.27969 | 0.00000 | 12.31098 -// 1 | 85 | 109.27913 | 28.09293 | 213.92493 | 214.26294 -// 2 | 523 | 1000.37159 | 7.26059 | 66.86342 | 66.77884 -// 3 | 570 | 1113.18458 | 0.00000 | 0.00000 | 0.00000 -// -// This is how the write delay look like (currently): -// DelayN:5 Delay:406.604657ms Paused: false -// -// This is how the iostats look like (currently): -// Read(MB):3895.04860 Write(MB):3654.64712 -func (db *Database) meter(refresh time.Duration) { +func (db *Database) meter(refresh time.Duration, namespace string) { // Create the counters to store current and previous compaction values - compactions := make([][]float64, 2) + compactions := make([][]int64, 2) for i := 0; i < 2; i++ { - compactions[i] = make([]float64, 4) + compactions[i] = make([]int64, 4) } - // Create storage for iostats. - var iostats [2]float64 - - // Create storage and warning log tracer for write delay. - var ( - delaystats [2]int64 - lastWritePaused time.Time - ) - + // Create storages for states and warning log tracer. var ( errc chan error merr error - ) + stats leveldb.DBStats + iostats [2]int64 + delaystats [2]int64 + lastWritePaused time.Time + ) timer := time.NewTimer(refresh) defer timer.Stop() // Iterate ad infinitum and collect the stats for i := 1; errc == nil && merr == nil; i++ { // Retrieve the database stats - stats, err := db.db.GetProperty("leveldb.stats") + // Stats method resets buffers inside therefore it's okay to just pass the struct. + err := db.db.Stats(&stats) if err != nil { db.log.Error("Failed to read database stats", "err", err) merr = err continue } - // Find the compaction table, skip the header - lines := strings.Split(stats, "\n") - for len(lines) > 0 && strings.TrimSpace(lines[0]) != "Compactions" { - lines = lines[1:] - } - if len(lines) <= 3 { - db.log.Error("Compaction leveldbTable not found") - merr = errors.New("compaction leveldbTable not found") - continue - } - lines = lines[3:] - // Iterate over all the leveldbTable rows, and accumulate the entries for j := 0; j < len(compactions[i%2]); j++ { compactions[i%2][j] = 0 } - for _, line := range lines { - parts := strings.Split(line, "|") - if len(parts) != 6 { - break - } - for idx, counter := range parts[2:] { - value, err := strconv.ParseFloat(strings.TrimSpace(counter), 64) - if err != nil { - db.log.Error("Compaction entry parsing failed", "err", err) - merr = err - continue - } - compactions[i%2][idx] += value - } + compactions[i%2][0] = stats.LevelSizes.Sum() + for _, t := range stats.LevelDurations { + compactions[i%2][1] += t.Nanoseconds() } + compactions[i%2][2] = stats.LevelRead.Sum() + compactions[i%2][3] = stats.LevelWrite.Sum() // Update all the requested meters if db.diskSizeGauge != nil { - db.diskSizeGauge.Update(int64(compactions[i%2][0] * 1024 * 1024)) + db.diskSizeGauge.Update(compactions[i%2][0]) } if db.compTimeMeter != nil { - db.compTimeMeter.Mark(int64((compactions[i%2][1] - compactions[(i-1)%2][1]) * 1000 * 1000 * 1000)) + db.compTimeMeter.Mark(compactions[i%2][1] - compactions[(i-1)%2][1]) } if db.compReadMeter != nil { - db.compReadMeter.Mark(int64((compactions[i%2][2] - compactions[(i-1)%2][2]) * 1024 * 1024)) + db.compReadMeter.Mark(compactions[i%2][2] - compactions[(i-1)%2][2]) } if db.compWriteMeter != nil { - db.compWriteMeter.Mark(int64((compactions[i%2][3] - compactions[(i-1)%2][3]) * 1024 * 1024)) - } - // Retrieve the write delay statistic - writedelay, err := db.db.GetProperty("leveldb.writedelay") - if err != nil { - db.log.Error("Failed to read database write delay statistic", "err", err) - merr = err - continue + db.compWriteMeter.Mark(compactions[i%2][3] - compactions[(i-1)%2][3]) } var ( - delayN int64 - delayDuration string - duration time.Duration - paused bool + delayN = int64(stats.WriteDelayCount) + duration = stats.WriteDelayDuration + paused = stats.WritePaused ) - if n, err := fmt.Sscanf(writedelay, "DelayN:%d Delay:%s Paused:%t", &delayN, &delayDuration, &paused); n != 3 || err != nil { - db.log.Error("Write delay statistic not found") - merr = err - continue - } - duration, err = time.ParseDuration(delayDuration) - if err != nil { - db.log.Error("Failed to parse delay duration", "err", err) - merr = err - continue - } if db.writeDelayNMeter != nil { db.writeDelayNMeter.Mark(delayN - delaystats[0]) } @@ -397,60 +338,30 @@ func (db *Database) meter(refresh time.Duration) { } delaystats[0], delaystats[1] = delayN, duration.Nanoseconds() - // Retrieve the database iostats. - ioStats, err := db.db.GetProperty("leveldb.iostats") - if err != nil { - db.log.Error("Failed to read database iostats", "err", err) - merr = err - continue - } - var nRead, nWrite float64 - parts := strings.Split(ioStats, " ") - if len(parts) < 2 { - db.log.Error("Bad syntax of ioStats", "ioStats", ioStats) - merr = fmt.Errorf("bad syntax of ioStats %s", ioStats) - continue - } - if n, err := fmt.Sscanf(parts[0], "Read(MB):%f", &nRead); n != 1 || err != nil { - db.log.Error("Bad syntax of read entry", "entry", parts[0]) - merr = err - continue - } - if n, err := fmt.Sscanf(parts[1], "Write(MB):%f", &nWrite); n != 1 || err != nil { - db.log.Error("Bad syntax of write entry", "entry", parts[1]) - merr = err - continue - } + var ( + nRead = int64(stats.IORead) + nWrite = int64(stats.IOWrite) + ) if db.diskReadMeter != nil { - db.diskReadMeter.Mark(int64((nRead - iostats[0]) * 1024 * 1024)) + db.diskReadMeter.Mark(nRead - iostats[0]) } if db.diskWriteMeter != nil { - db.diskWriteMeter.Mark(int64((nWrite - iostats[1]) * 1024 * 1024)) + db.diskWriteMeter.Mark(nWrite - iostats[1]) } iostats[0], iostats[1] = nRead, nWrite - compCount, err := db.db.GetProperty("leveldb.compcount") - if err != nil { - db.log.Error("Failed to read database iostats", "err", err) - merr = err - continue - } + db.memCompGauge.Update(int64(stats.MemComp)) + db.level0CompGauge.Update(int64(stats.Level0Comp)) + db.nonlevel0CompGauge.Update(int64(stats.NonLevel0Comp)) + db.seekCompGauge.Update(int64(stats.SeekComp)) - var ( - memComp uint32 - level0Comp uint32 - nonLevel0Comp uint32 - seekComp uint32 - ) - if n, err := fmt.Sscanf(compCount, "MemComp:%d Level0Comp:%d NonLevel0Comp:%d SeekComp:%d", &memComp, &level0Comp, &nonLevel0Comp, &seekComp); n != 4 || err != nil { - db.log.Error("Compaction count statistic not found") - merr = err - continue + for i, tables := range stats.LevelTablesCounts { + // Append metrics for additional layers + if i >= len(db.levelsGauge) { + db.levelsGauge = append(db.levelsGauge, metrics.NewRegisteredGauge(namespace+fmt.Sprintf("tables/level%v", i), nil)) + } + db.levelsGauge[i].Update(int64(tables)) } - db.memCompGauge.Update(int64(memComp)) - db.level0CompGauge.Update(int64(level0Comp)) - db.nonlevel0CompGauge.Update(int64(nonLevel0Comp)) - db.seekCompGauge.Update(int64(seekComp)) // Sleep a bit, then repeat the stats collection select { diff --git a/ethdb/memorydb/memorydb.go b/ethdb/memorydb/memorydb.go index 6ca7ce7d91..f9f74322b5 100644 --- a/ethdb/memorydb/memorydb.go +++ b/ethdb/memorydb/memorydb.go @@ -244,6 +244,9 @@ func (b *batch) Write() error { b.db.lock.Lock() defer b.db.lock.Unlock() + if b.db.db == nil { + return errMemorydbClosed + } for _, keyvalue := range b.writes { if keyvalue.delete { delete(b.db.db, string(keyvalue.key)) diff --git a/ethdb/pebble/pebble.go b/ethdb/pebble/pebble.go index 5be4c1af73..12a84cc91a 100644 --- a/ethdb/pebble/pebble.go +++ b/ethdb/pebble/pebble.go @@ -70,8 +70,9 @@ type Database struct { seekCompGauge metrics.Gauge // Gauge for tracking the number of table compaction caused by read opt manualMemAllocGauge metrics.Gauge // Gauge for tracking amount of non-managed memory currently allocated - quitLock sync.Mutex // Mutex protecting the quit channel access + quitLock sync.RWMutex // Mutex protecting the quit channel and the closed flag quitChan chan chan error // Quit channel to stop the metrics collection before closing the database + closed bool // keep track of whether we're Closed log log.Logger // Contextual logger tracking the database path @@ -83,6 +84,8 @@ type Database struct { 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 } func (d *Database) onCompactionBegin(info pebble.CompactionInfo) { @@ -117,7 +120,7 @@ func (d *Database) onWriteStallEnd() { // New returns a wrapped pebble DB object. The namespace is the prefix that the // metrics reporting should use for surfacing internal stats. -func New(file string, cache int, handles int, namespace string, readonly bool) (*Database, error) { +func New(file string, cache int, handles int, namespace string, readonly bool, ephemeral bool) (*Database, error) { // Ensure we have some minimal caching and file guarantees if cache < minCache { cache = minCache @@ -141,9 +144,10 @@ func New(file string, cache int, handles int, namespace string, readonly bool) ( memTableSize = maxMemTableSize } db := &Database{ - fn: file, - log: logger, - quitChan: make(chan chan error), + fn: file, + log: logger, + quitChan: make(chan chan error), + writeOptions: &pebble.WriteOptions{Sync: !ephemeral}, } opt := &pebble.Options{ // Pebble has a single combined cache area and the write @@ -221,23 +225,29 @@ func New(file string, cache int, handles int, namespace string, readonly bool) ( func (d *Database) Close() error { d.quitLock.Lock() defer d.quitLock.Unlock() - // Allow double closing, simplifies things - if d.quitChan == nil { + if d.closed { return nil } - errc := make(chan error) - d.quitChan <- errc - if err := <-errc; err != nil { - d.log.Error("Metrics collection failed", "err", err) + d.closed = true + if d.quitChan != nil { + errc := make(chan error) + d.quitChan <- errc + if err := <-errc; err != nil { + d.log.Error("Metrics collection failed", "err", err) + } + d.quitChan = nil } - d.quitChan = nil - return d.db.Close() } // Has retrieves if a key is present in the key-value store. func (d *Database) Has(key []byte) (bool, error) { + d.quitLock.RLock() + defer d.quitLock.RUnlock() + if d.closed { + return false, pebble.ErrClosed + } _, closer, err := d.db.Get(key) if err == pebble.ErrNotFound { return false, nil @@ -250,6 +260,11 @@ func (d *Database) Has(key []byte) (bool, error) { // Get retrieves the given key if it's present in the key-value store. func (d *Database) Get(key []byte) ([]byte, error) { + d.quitLock.RLock() + defer d.quitLock.RUnlock() + if d.closed { + return nil, pebble.ErrClosed + } dat, closer, err := d.db.Get(key) if err != nil { return nil, err @@ -262,11 +277,21 @@ func (d *Database) Get(key []byte) ([]byte, error) { // Put inserts the given value into the key-value store. func (d *Database) Put(key []byte, value []byte) error { - return d.db.Set(key, value, pebble.NoSync) + d.quitLock.RLock() + defer d.quitLock.RUnlock() + if d.closed { + return pebble.ErrClosed + } + return d.db.Set(key, value, d.writeOptions) } // Delete removes the key from the key-value store. func (d *Database) Delete(key []byte) error { + d.quitLock.RLock() + defer d.quitLock.RUnlock() + if d.closed { + return pebble.ErrClosed + } return d.db.Delete(key, nil) } @@ -274,7 +299,8 @@ func (d *Database) Delete(key []byte) error { // database until a final write is called. func (d *Database) NewBatch() ethdb.Batch { return &batch{ - b: d.db.NewBatch(), + b: d.db.NewBatch(), + db: d, } } @@ -284,7 +310,8 @@ func (d *Database) NewBatch() ethdb.Batch { // batch object without any pre-allocated space. func (d *Database) NewBatchWithSize(_ int) ethdb.Batch { return &batch{ - b: d.db.NewBatch(), + b: d.db.NewBatch(), + db: d, } } @@ -481,6 +508,7 @@ func (d *Database) meter(refresh time.Duration) { // when Write is called. A batch cannot be used concurrently. type batch struct { b *pebble.Batch + db *Database size int } @@ -505,7 +533,12 @@ func (b *batch) ValueSize() int { // Write flushes any accumulated data to disk. func (b *batch) Write() error { - return b.b.Commit(pebble.NoSync) + b.db.quitLock.RLock() + defer b.db.quitLock.RUnlock() + if b.db.closed { + return pebble.ErrClosed + } + return b.b.Commit(b.db.writeOptions) } // Reset resets the batch for reuse. diff --git a/ethdb/remotedb/remotedb.go b/ethdb/remotedb/remotedb.go index 9ce657d780..c1c803caf2 100644 --- a/ethdb/remotedb/remotedb.go +++ b/ethdb/remotedb/remotedb.go @@ -98,11 +98,11 @@ func (db *Database) ModifyAncients(f func(ethdb.AncientWriteOp) error) (int64, e panic("not supported") } -func (db *Database) TruncateHead(n uint64) error { +func (db *Database) TruncateHead(n uint64) (uint64, error) { panic("not supported") } -func (db *Database) TruncateTail(n uint64) error { +func (db *Database) TruncateTail(n uint64) (uint64, error) { panic("not supported") } diff --git a/event/feed.go b/event/feed.go index 33dafe5886..d94bd820f0 100644 --- a/event/feed.go +++ b/event/feed.go @@ -57,7 +57,8 @@ func (e feedTypeError) Error() string { return "event: wrong type in " + e.op + " got " + e.got.String() + ", want " + e.want.String() } -func (f *Feed) init() { +func (f *Feed) init(etype reflect.Type) { + f.etype = etype f.removeSub = make(chan interface{}) f.sendLock = make(chan struct{}, 1) f.sendLock <- struct{}{} @@ -70,8 +71,6 @@ func (f *Feed) init() { // The channel should have ample buffer space to avoid blocking other subscribers. // Slow subscribers are not dropped. func (f *Feed) Subscribe(channel interface{}) Subscription { - f.once.Do(f.init) - chanval := reflect.ValueOf(channel) chantyp := chanval.Type() if chantyp.Kind() != reflect.Chan || chantyp.ChanDir()&reflect.SendDir == 0 { @@ -79,11 +78,13 @@ func (f *Feed) Subscribe(channel interface{}) Subscription { } sub := &feedSub{feed: f, channel: chanval, err: make(chan error, 1)} - f.mu.Lock() - defer f.mu.Unlock() - if !f.typecheck(chantyp.Elem()) { + f.once.Do(func() { f.init(chantyp.Elem()) }) + if f.etype != chantyp.Elem() { panic(feedTypeError{op: "Subscribe", got: chantyp, want: reflect.ChanOf(reflect.SendDir, f.etype)}) } + + f.mu.Lock() + defer f.mu.Unlock() // Add the select case to the inbox. // The next Send will add it to f.sendCases. cas := reflect.SelectCase{Dir: reflect.SelectSend, Chan: chanval} @@ -91,15 +92,6 @@ func (f *Feed) Subscribe(channel interface{}) Subscription { return sub } -// note: callers must hold f.mu -func (f *Feed) typecheck(typ reflect.Type) bool { - if f.etype == nil { - f.etype = typ - return true - } - return f.etype == typ -} - func (f *Feed) remove(sub *feedSub) { // Delete from inbox first, which covers channels // that have not been added to f.sendCases yet. @@ -128,19 +120,17 @@ func (f *Feed) remove(sub *feedSub) { func (f *Feed) Send(value interface{}) (nsent int) { rvalue := reflect.ValueOf(value) - f.once.Do(f.init) + f.once.Do(func() { f.init(rvalue.Type()) }) + if f.etype != rvalue.Type() { + panic(feedTypeError{op: "Send", got: rvalue.Type(), want: f.etype}) + } + <-f.sendLock // Add new cases from the inbox after taking the send lock. f.mu.Lock() f.sendCases = append(f.sendCases, f.inbox...) f.inbox = nil - - if !f.typecheck(rvalue.Type()) { - f.sendLock <- struct{}{} - f.mu.Unlock() - panic(feedTypeError{op: "Send", got: rvalue.Type(), want: f.etype}) - } f.mu.Unlock() // Set the sent value on all channels. diff --git a/event/feed_test.go b/event/feed_test.go index cdf29fdd73..74e8587a87 100644 --- a/event/feed_test.go +++ b/event/feed_test.go @@ -17,6 +17,7 @@ package event import ( + "errors" "fmt" "reflect" "sync" @@ -68,7 +69,7 @@ func checkPanic(want error, fn func()) (err error) { defer func() { panic := recover() if panic == nil { - err = fmt.Errorf("didn't panic") + err = errors.New("didn't panic") } else if !reflect.DeepEqual(panic, want) { err = fmt.Errorf("panicked with wrong error: got %q, want %q", panic, want) } diff --git a/event/multisub.go b/event/multisub.go new file mode 100644 index 0000000000..5c8d2df48c --- /dev/null +++ b/event/multisub.go @@ -0,0 +1,50 @@ +// 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 event + +// JoinSubscriptions joins multiple subscriptions to be able to track them as +// one entity and collectively cancel them of consume any errors from them. +func JoinSubscriptions(subs ...Subscription) Subscription { + return NewSubscription(func(unsubbed <-chan struct{}) error { + // Unsubscribe all subscriptions before returning + defer func() { + for _, sub := range subs { + sub.Unsubscribe() + } + }() + // Wait for an error on any of the subscriptions and propagate up + errc := make(chan error, len(subs)) + for i := range subs { + go func(sub Subscription) { + select { + case err := <-sub.Err(): + if err != nil { + errc <- err + } + case <-unsubbed: + } + }(subs[i]) + } + + select { + case err := <-errc: + return err + case <-unsubbed: + return nil + } + }) +} diff --git a/event/multisub_test.go b/event/multisub_test.go new file mode 100644 index 0000000000..c92bcfae9b --- /dev/null +++ b/event/multisub_test.go @@ -0,0 +1,175 @@ +// 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 event + +import ( + "testing" + "time" +) + +func TestMultisub(t *testing.T) { + // Create a double subscription and ensure events propagate through + var ( + feed1 Feed + feed2 Feed + ) + sink1 := make(chan int, 1) + sink2 := make(chan int, 1) + + sub1 := feed1.Subscribe(sink1) + sub2 := feed2.Subscribe(sink2) + + sub := JoinSubscriptions(sub1, sub2) + + feed1.Send(1) + select { + case n := <-sink1: + if n != 1 { + t.Errorf("sink 1 delivery mismatch: have %d, want %d", n, 1) + } + default: + t.Error("sink 1 missing delivery") + } + + feed2.Send(2) + select { + case n := <-sink2: + if n != 2 { + t.Errorf("sink 2 delivery mismatch: have %d, want %d", n, 2) + } + default: + t.Error("sink 2 missing delivery") + } + // Unsubscribe and ensure no more events are delivered + sub.Unsubscribe() + select { + case <-sub.Err(): + case <-time.After(50 * time.Millisecond): + t.Error("multisub didn't propagate closure") + } + + feed1.Send(11) + select { + case n := <-sink1: + t.Errorf("sink 1 unexpected delivery: %d", n) + default: + } + + feed2.Send(22) + select { + case n := <-sink2: + t.Errorf("sink 2 unexpected delivery: %d", n) + default: + } +} + +func TestMutisubPartialUnsubscribe(t *testing.T) { + // Create a double subscription but terminate one half, ensuring no error + // is propagated yet up to the outer subscription + var ( + feed1 Feed + feed2 Feed + ) + sink1 := make(chan int, 1) + sink2 := make(chan int, 1) + + sub1 := feed1.Subscribe(sink1) + sub2 := feed2.Subscribe(sink2) + + sub := JoinSubscriptions(sub1, sub2) + + sub1.Unsubscribe() + select { + case <-sub.Err(): + t.Error("multisub propagated closure") + case <-time.After(50 * time.Millisecond): + } + // Ensure that events cross only the second feed + feed1.Send(1) + select { + case n := <-sink1: + t.Errorf("sink 1 unexpected delivery: %d", n) + default: + } + + feed2.Send(2) + select { + case n := <-sink2: + if n != 2 { + t.Errorf("sink 2 delivery mismatch: have %d, want %d", n, 2) + } + default: + t.Error("sink 2 missing delivery") + } + // Unsubscribe and ensure no more events are delivered + sub.Unsubscribe() + select { + case <-sub.Err(): + case <-time.After(50 * time.Millisecond): + t.Error("multisub didn't propagate closure") + } + + feed1.Send(11) + select { + case n := <-sink1: + t.Errorf("sink 1 unexpected delivery: %d", n) + default: + } + + feed2.Send(22) + select { + case n := <-sink2: + t.Errorf("sink 2 unexpected delivery: %d", n) + default: + } +} + +func TestMultisubFullUnsubscribe(t *testing.T) { + // Create a double subscription and terminate the multi sub, ensuring an + // error is propagated up. + var ( + feed1 Feed + feed2 Feed + ) + sink1 := make(chan int, 1) + sink2 := make(chan int, 1) + + sub1 := feed1.Subscribe(sink1) + sub2 := feed2.Subscribe(sink2) + + sub := JoinSubscriptions(sub1, sub2) + sub.Unsubscribe() + select { + case <-sub.Err(): + case <-time.After(50 * time.Millisecond): + t.Error("multisub didn't propagate closure") + } + // Ensure no more events are delivered + feed1.Send(1) + select { + case n := <-sink1: + t.Errorf("sink 1 unexpected delivery: %d", n) + default: + } + + feed2.Send(2) + select { + case n := <-sink2: + t.Errorf("sink 2 unexpected delivery: %d", n) + default: + } +} diff --git a/go.mod b/go.mod index 7061e69466..cf242e9d2d 100644 --- a/go.mod +++ b/go.mod @@ -1,9 +1,10 @@ module github.com/ethereum/go-ethereum -go 1.19 +go 1.20 require ( github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0 + github.com/Microsoft/go-winio v0.6.1 github.com/VictoriaMetrics/fastcache v1.6.0 github.com/aws/aws-sdk-go-v2 v1.2.0 github.com/aws/aws-sdk-go-v2/config v1.1.1 @@ -12,21 +13,20 @@ require ( github.com/btcsuite/btcd/btcec/v2 v2.2.0 github.com/cespare/cp v0.1.0 github.com/cloudflare/cloudflare-go v0.14.0 - github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811 + github.com/cockroachdb/pebble v0.0.0-20230906160148-46873a6a7a06 github.com/consensys/gnark-crypto v0.10.0 - github.com/crate-crypto/go-kzg-4844 v0.2.0 + github.com/crate-crypto/go-kzg-4844 v0.3.0 github.com/davecgh/go-spew v1.1.1 github.com/deckarep/golang-set/v2 v2.1.0 - github.com/docker/docker v1.6.2 - github.com/dop251/goja v0.0.0-20230122112309-96b1610dd4f7 - github.com/edsrzf/mmap-go v1.0.0 - github.com/ethereum/c-kzg-4844 v0.2.0 + github.com/docker/docker v24.0.5+incompatible + github.com/dop251/goja v0.0.0-20230806174421-c933cf95e127 + github.com/ethereum/c-kzg-4844 v0.3.1 github.com/fatih/color v1.7.0 - github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c + github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 github.com/fsnotify/fsnotify v1.6.0 github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff - github.com/gballet/go-verkle v0.0.0-20220902153445-097bd83b7732 + github.com/gballet/go-verkle v0.0.0-20230607174250-df487255f46b github.com/go-stack/stack v1.8.1 github.com/gofrs/flock v0.8.1 github.com/golang-jwt/jwt/v4 v4.3.0 @@ -37,73 +37,79 @@ require ( github.com/gorilla/websocket v1.4.2 github.com/graph-gophers/graphql-go v1.3.0 github.com/hashicorp/go-bexpr v0.1.10 + github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7 github.com/holiman/bloomfilter/v2 v2.0.3 - github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c - github.com/huin/goupnp v1.0.3 + github.com/holiman/uint256 v1.2.3 + 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 github.com/jackpal/go-nat-pmp v1.0.2 - github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e + 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/usb v0.0.3-0.20230711191512-61db3e06439c github.com/kylelemons/godebug v1.1.0 github.com/mattn/go-colorable v0.1.13 github.com/mattn/go-isatty v0.0.16 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/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.1 - github.com/supranational/blst v0.3.11-0.20230406105308-e9dfc5ee724b + 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 - github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa - golang.org/x/crypto v0.1.0 - golang.org/x/exp v0.0.0-20230206171751-46f607a40771 - golang.org/x/sync v0.1.0 - golang.org/x/sys v0.7.0 - golang.org/x/text v0.8.0 - golang.org/x/time v0.0.0-20220922220347-f3bd1da661af - golang.org/x/tools v0.7.0 + github.com/urfave/cli/v2 v2.24.1 + go.uber.org/automaxprocs v1.5.2 + golang.org/x/crypto v0.12.0 + golang.org/x/exp v0.0.0-20230810033253-352e893a4cad + golang.org/x/sync v0.3.0 + golang.org/x/sys v0.11.0 + golang.org/x/text v0.12.0 + golang.org/x/time v0.3.0 + golang.org/x/tools v0.9.1 gopkg.in/natefinch/lumberjack.v2 v2.0.0 - gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce + gopkg.in/yaml.v3 v3.0.1 ) require ( github.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3 // indirect - github.com/DataDog/zstd v1.5.2 // indirect - github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 // indirect + github.com/DataDog/zstd v1.4.5 // indirect + github.com/StackExchange/wmi v1.2.1 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.0.2 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.0.2 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.1.1 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.1.1 // indirect github.com/aws/smithy-go v1.1.0 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/bits-and-blooms/bitset v1.7.0 // indirect + github.com/bits-and-blooms/bitset v1.5.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/cockroachdb/errors v1.9.1 // indirect - github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect - github.com/cockroachdb/redact v1.1.3 // 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/consensys/bavard v0.1.13 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect - github.com/crate-crypto/go-ipa v0.0.0-20220523130400-f11357ae11c7 // indirect + github.com/crate-crypto/go-ipa v0.0.0-20230601170251-1830d0757c80 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect - github.com/deepmap/oapi-codegen v1.8.2 // indirect + 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.2.1 // indirect + github.com/go-ole/go-ole v1.2.5 // indirect github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 // indirect + github.com/google/go-cmp v0.5.9 // indirect + github.com/google/pprof v0.0.0-20230207041349-798e818bf904 // indirect + github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 // indirect + github.com/kilic/bls12-381 v0.1.0 // indirect github.com/klauspost/compress v1.15.15 // indirect - github.com/kr/pretty v0.3.1 // indirect + github.com/kr/pretty v0.3.0 // indirect github.com/kr/text v0.2.0 // indirect github.com/mattn/go-runewidth v0.0.9 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect github.com/mitchellh/mapstructure v1.4.1 // indirect github.com/mitchellh/pointerstructure v1.2.0 // indirect github.com/mmcloughlin/addchain v0.4.0 // indirect @@ -111,20 +117,19 @@ require ( github.com/opentracing/opentracing-go v1.1.0 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_golang v1.14.0 // indirect - github.com/prometheus/client_model v0.3.0 // indirect - github.com/prometheus/common v0.39.0 // indirect - github.com/prometheus/procfs v0.9.0 // indirect - github.com/rogpeppe/go-internal v1.9.0 // indirect + github.com/prometheus/client_golang v1.12.0 // indirect + github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a // indirect + github.com/prometheus/common v0.32.1 // indirect + github.com/prometheus/procfs v0.7.3 // indirect + github.com/rogpeppe/go-internal v1.6.1 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/tklauser/go-sysconf v0.3.5 // indirect - github.com/tklauser/numcpus v0.2.2 // indirect + 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/mod v0.9.0 // indirect - golang.org/x/net v0.8.0 // indirect - golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect - google.golang.org/protobuf v1.28.1 // indirect + golang.org/x/mod v0.11.0 // indirect + golang.org/x/net v0.10.0 // indirect + google.golang.org/protobuf v1.27.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect + gotest.tools/v3 v3.5.0 // indirect rsc.io/tmplfunc v0.0.3 // indirect ) diff --git a/go.sum b/go.sum index 6a31436ec9..4cb3a1bb88 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,36 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +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 v0.21.1 h1:qoVeMsc9/fh/yhxVaA0obYjVH/oI/ihrOoMwsLS9KSA= github.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1/go.mod h1:fBF9PQNqB8scdgpZ3ufzaLntG0AG7C1WjPMsiFOmfHM= @@ -7,18 +39,27 @@ github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3/go.mod h1:KLF4gFr6DcKFZwSu github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0 h1:Px2UA+2RvSSvv+RvJNuUB6n7rs5Wsel4dXLe90Um2n4= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0/go.mod h1:tPaiy8S5bQ+S5sOiDlINkp7+Ef339+Nz5L5XO+cnOHo= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.2.0 h1:Rt8g24XnyGTyglgET/PRUNlrUeu9F5L+7FilkXfZgs0= -github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= -github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo= -github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8= -github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= +github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak= +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 v0.0.0-20180116203802-5d049714c4a6 h1:fLjPD/aNc3UIOA6tDi6QXUemppXK3P9BI7mr2hd6gx8= -github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= +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.6.0 h1:C/3Oi3EiBCqufydp1neRZkqcwmEiuRT9c3fqvvgKm5o= github.com/VictoriaMetrics/fastcache v1.6.0/go.mod h1:0qHz5QP0GMX4pfmMA/zt5RgfNuXJrTP0zS7DqpHGGTw= 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= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +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= @@ -41,12 +82,12 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.1.1/go.mod h1:Wi0EBZwiz/K44YliU0EKxq github.com/aws/smithy-go v1.1.0 h1:D6CSsM3gdxaGaqXnPgOBCeL6Mophqzu7KJOu7zW78sU= github.com/aws/smithy-go v1.1.0/go.mod h1:EzMw8dbp/YJL4A5/sbhGddag+NPT7q084agLbB9LgIw= 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= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bits-and-blooms/bitset v1.5.0 h1:NpE8frKRLGHIcEzkR+gZhiioW1+WbYV6fKwD6ZIpQT8= github.com/bits-and-blooms/bitset v1.5.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= -github.com/bits-and-blooms/bitset v1.7.0 h1:YjAGVd3XmtK9ktAbX8Zg2g2PwLIMjGREZJHlV4j7NEo= -github.com/bits-and-blooms/bitset v1.7.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= 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= @@ -54,23 +95,32 @@ github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA 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/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= +github.com/chzyer/readline v1.5.0/go.mod h1:x22KAscuvRqlLoK9CsoYsmxoXZMMFVyOl86cAH8qUic= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/chzyer/test v0.0.0-20210722231415-061457976a23/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/cloudflare-go v0.14.0 h1:gFqGlGl/5f9UGXAaKapCGUfaTCgRKKnzu2VvzMZlOFA= github.com/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3hQ7C/YWzIGLeu5c304= -github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cockroachdb/datadriven v1.0.2 h1:H9MtNqVoVhvd9nCBwOyDjUEdZCREqbIdCJD93PBm/jA= -github.com/cockroachdb/datadriven v1.0.2/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= -github.com/cockroachdb/errors v1.9.1 h1:yFVvsI0VxmRShfawbt/laCIDy/mtTqqnvoNgiy5bEV8= -github.com/cockroachdb/errors v1.9.1/go.mod h1:2sxOtL2WIc096WSZqZ5h8fa17rdDq9HZOZLBCor4mBk= -github.com/cockroachdb/logtags v0.0.0-20211118104740-dabe8e521a4f/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= -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 v0.0.0-20230209160836-829675f94811 h1:ytcWPaNPhNoGMWEhDvS3zToKcDpRsLuRolQJBVGdozk= -github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811/go.mod h1:Nb5lgvnQ2+oGlE/EyZy4+2/CxRh9KfvCXnag1vtpxVM= -github.com/cockroachdb/redact v1.1.3 h1:AKZds10rFSIj7qADf0g46UixK8NNLwWTNdCIGS5wfSQ= -github.com/cockroachdb/redact v1.1.3/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= +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.20230801171734-e384cf455877 h1:1MLK4YpFtIEo3ZtMA5C795Wtv5VuUnrXX7mQG+aHg6o= +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-20230906160148-46873a6a7a06 h1:T+Np/xtzIjYM/P5NAw0e2Rf1FGvzDau1h54MKvx8G7w= +github.com/cockroachdb/pebble v0.0.0-20230906160148-46873a6a7a06/go.mod h1:bynZ3gvVyhlvjLI7PT6dmZ7g76xzJ7HpxfjgkzCGz6s= +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/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= @@ -83,12 +133,10 @@ github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwc github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= 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-20220523130400-f11357ae11c7 h1:6IrxszG5G+O7zhtkWxq6+unVvnrm1fqV2Pe+T95DUzw= -github.com/crate-crypto/go-ipa v0.0.0-20220523130400-f11357ae11c7/go.mod h1:gFnFS95y8HstDP6P9pPwzrxOOC5TRDkwbM+ao15ChAI= -github.com/crate-crypto/go-kzg-4844 v0.1.0 h1:2PXr2wKBNTmSsoYLCmaNg5Z6uQUf7LiUAsnDbTfq+0M= -github.com/crate-crypto/go-kzg-4844 v0.1.0/go.mod h1:SBP7ikXEgDnUPONgm33HtuDZEDtWa3L4QtN1ocJSEQ4= -github.com/crate-crypto/go-kzg-4844 v0.2.0 h1:UVuHOE+5tIWrim4zf/Xaa43+MIsDCPyW76QhUpiMGj4= -github.com/crate-crypto/go-kzg-4844 v0.2.0/go.mod h1:SBP7ikXEgDnUPONgm33HtuDZEDtWa3L4QtN1ocJSEQ4= +github.com/crate-crypto/go-ipa v0.0.0-20230601170251-1830d0757c80 h1:DuBDHVjgGMPki7bAyh91+3cF1Vh34sAEdH8JQgbc2R0= +github.com/crate-crypto/go-ipa v0.0.0-20230601170251-1830d0757c80/go.mod h1:gzbVz57IDJgQ9rLQwfSk696JGWof8ftznEL9GoAv3NI= +github.com/crate-crypto/go-kzg-4844 v0.3.0 h1:UBlWE0CgyFqqzTI+IFyCzA7A3Zw4iip6uzRv5NIXG0A= +github.com/crate-crypto/go-kzg-4844 v0.3.0/go.mod h1:SBP7ikXEgDnUPONgm33HtuDZEDtWa3L4QtN1ocJSEQ4= 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= @@ -100,9 +148,8 @@ github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK 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= 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/deepmap/oapi-codegen v1.8.2 h1:SegyeYGcdi0jLLrpbCMoJxnUUn8GBXHsvr4rbzjuhfU= -github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRktEqrX88CvjIw= 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= @@ -112,34 +159,31 @@ github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnm github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= 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/docker/docker v1.6.2 h1:HlFGsy+9/xrgMmhmN+NGhCc5SHGJ7I+kHosRR1xc/aI= -github.com/docker/docker v1.6.2/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v24.0.5+incompatible h1:WmgcE4fxyI6EEXxBRxsHnZXrO1pQ3smi0k/jho4HLeY= +github.com/docker/docker v24.0.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/dop251/goja v0.0.0-20211022113120-dc8c55024d06/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= -github.com/dop251/goja v0.0.0-20230122112309-96b1610dd4f7 h1:kgvzE5wLsLa7XKfV85VZl40QXaMCaeFtHpPwJ8fhotY= -github.com/dop251/goja v0.0.0-20230122112309-96b1610dd4f7/go.mod h1:yRkwfj0CBpOGre+TwBsqPV0IH0Pk73e4PXJOeNDboGs= +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_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/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= -github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= 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.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +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.1.0 h1:BR9kUo6zAaFphuoNj39NquE3Sl0sD/oT0+idKZ4mkiI= -github.com/ethereum/c-kzg-4844 v0.1.0/go.mod h1:WI2Nd82DMZAAZI1wV2neKGost9EKjvbpQR9OqE5Qqa8= -github.com/ethereum/c-kzg-4844 v0.2.0 h1:+cUvymlnoDDQgMInp25Bo3OmLajmmY8mLJ/tLjqd77Q= -github.com/ethereum/c-kzg-4844 v0.2.0/go.mod h1:WI2Nd82DMZAAZI1wV2neKGost9EKjvbpQR9OqE5Qqa8= +github.com/ethereum/c-kzg-4844 v0.3.1 h1:sR65+68+WdnMKxseNWxSJuAv2tsUrihTpVBTfM/U5Zg= +github.com/ethereum/c-kzg-4844 v0.3.1/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= -github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c h1:CndMRAH4JIwxbW8KYq6Q+cGWcGHz0FjGR3QqcInWcW0= -github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c/go.mod h1:AzA8Lj6YtixmJWL+wkKoBGsLWy9gFrAzi4g+5bCKwpY= +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.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c= github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/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= @@ -149,27 +193,33 @@ github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61/go.mod h1:Q0X6pkwTILD 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.0.0-20220902153445-097bd83b7732 h1:AB7YjNrzlVHsYz06zCULVV2zYCEft82P86dSmtwxKL0= -github.com/gballet/go-verkle v0.0.0-20220902153445-097bd83b7732/go.mod h1:o/XfIXWi4/GqbQirfRm5uTbXMG5NpqxkxblnbZ+QM9I= +github.com/gballet/go-verkle v0.0.0-20230607174250-df487255f46b h1:vMT47RYsrftsHSTQhqXwC3BYflo38OLC3Y4LtXtLyU0= +github.com/gballet/go-verkle v0.0.0-20230607174250-df487255f46b/go.mod h1:CDncRYVRSDqwakm282WEkjfaAj1hxU/v5RXxk5nXOiI= github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= -github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= -github.com/getsentry/sentry-go v0.12.0/go.mod h1:NSap0JBYWzHND8oMbyi0+XZhUalc1TBdRL1M71JZW2c= -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= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +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.1 h1:2lOsA72HgjxAuMlKpFiCbHTvu44PIVkZ5hqm3RSdI/E= -github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= +github.com/go-ole/go-ole v1.2.5 h1:t4MGB5xEDZvXI+0rMjjsfBsD7yAgp/s9ZDkL1JndXwY= +github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= 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/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= @@ -178,19 +228,30 @@ github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/E 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/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4= +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 v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v4 v4.3.0 h1:kHL1vqdqWNfATmA0FNMdmZNMyZI1U6O31X4rlIPoBog= github.com/golang-jwt/jwt/v4 v4.3.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= @@ -199,6 +260,7 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +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 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= @@ -208,26 +270,43 @@ github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXi 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= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 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/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa h1:Q75Upo5UN4JbPFURXZ8nLKYUvF85dyFRop/vQ0Rv+64= github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20230207041349-798e818bf904 h1:4/hN5RUoecvl+RmJRE2YxKWtnnQls6rQjjW5oV7qg2U= +github.com/google/pprof v0.0.0-20230207041349-798e818bf904/go.mod h1:uglQLonpP8qtYCYyzA+8c/9qtqgA3qsXGYqCPKARAFg= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 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.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +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= @@ -235,69 +314,85 @@ github.com/graph-gophers/graphql-go v1.3.0/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLt github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= 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-20230718173358-1c7e68d277a7 h1:3JQNjnMRil1yD0IfZKHF9GxxWKDJGj8I0IqOUol//sw= +github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7/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.2-0.20230321075855-87b91420868c h1:DZfsyhDK1hnSS5lH8l+JggqzEleHteTYfutAiVlSUM8= -github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw= +github.com/holiman/uint256 v1.2.3 h1:K8UWO1HUJpRMXBxbmaY1Y8IAMZC/RsKB+ArEnnK4l5o= +github.com/holiman/uint256 v1.2.3/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ= -github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y= -github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= -github.com/hydrogen18/memlistener v0.0.0-20200120041712-dcc25e7acd91/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= +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/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 h1:vilfsDSy7TDxedi9gyBkMvAirat/oRcL0lFdJBf6tdM= -github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097/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/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk= -github.com/iris-contrib/pongo2 v0.0.1/go.mod h1:Ssh+00+3GAZqSQb30AvBRNxBx7rf0GqwkjqxNd0u65g= +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-20190909160543-45766022959e h1:UvSe12bq+Uj2hWd8aOlwPmoZ+CITRFrdit+sDGfAg8U= -github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU= +github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267 h1:TMtDYDHKYY15rFihtRfck/bfFqNfvcabqvXAFQfAUpY= +github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267/go.mod h1:h1nSAbGFqGVzn6Jyl1R/iCcBUHN4g+gW1u9CoBTrb9E= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +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/usb v0.0.2 h1:M6QQBNxF+CQ8OFvxrT90BA0qBOXymndZnk5q235mFc4= -github.com/karalabe/usb v0.0.2/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= -github.com/kataras/golog v0.0.10/go.mod h1:yJ8YKCmyL+nWjERB90Qwn+bdyBZsaQwU3bTVFgkFIp8= -github.com/kataras/iris/v12 v12.1.8/go.mod h1:LMYy4VlP67TQ3Zgriz8RE2h2kMZV2SgMYbq3UhfoFmE= -github.com/kataras/neffos v0.0.14/go.mod h1:8lqADm8PnbeFfL7CLXh1WHw53dG27MC3pgi2R1rmoTE= -github.com/kataras/pio v0.0.2/go.mod h1:hAoW0t9UmXi4R5Oyq5Z4irTbaTsOemSrDGUtaTl7Dro= -github.com/kataras/sitemap v0.0.5/go.mod h1:KY2eugMKiPwsJgx7+U103YZehfvNGOXURubcGyk0Bz8= +github.com/karalabe/usb v0.0.3-0.20230711191512-61db3e06439c h1:AqsttAyEyIEsNz5WLRwuRwjiT5CMDUfLk6cFJDVPebs= +github.com/karalabe/usb v0.0.3-0.20230711191512-61db3e06439c/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= +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.7/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/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 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/echo/v4 v4.5.0/go.mod h1:czIriw4a0C1dFun+ObrXp7ok03xON0N1awStJ6ArI7Y= 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= @@ -308,23 +403,23 @@ 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.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= 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= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= -github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= -github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8= +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/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= @@ -339,23 +434,25 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 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/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= 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/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= -github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= -github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +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.10.3/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= @@ -368,25 +465,41 @@ github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 h1:oYW+YCJ1pachXTQm 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/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= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= -github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= +github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= +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= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.0 h1:C+UIj/QWtmqY13Arb8kwMt5j34/0Z2iKamrJ+ryC0Gg= +github.com/prometheus/client_golang v1.12.0/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= -github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= -github.com/prometheus/common v0.39.0 h1:oOyhkDq05hPZKItWVBkJ6g6AtGxi+fy7F4JvUV8uhsI= -github.com/prometheus/common v0.39.0/go.mod h1:6XBZ7lYdLCbkAVhwRsWTZn+IN5AB9F/NXd5w0BbEX0Y= -github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= -github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a h1:CmF68hwI0XsOQ5UwlBopMi2Ow4Pbg32akc4KIVCOm+Y= +github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +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-20220416220906-d8552aa452c7 h1:cZC+usqsYgHtlBaGulVnZ1hfKAi8iWtujBnRLQE698c= +github.com/protolambda/bls12-381-util v0.0.0-20220416220906-d8552aa452c7/go.mod h1:IToEjHuttnUzwZI5KBSM/LOOW3qLbbrHOEfp3SbECGY= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= -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= @@ -394,11 +507,14 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD 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/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g= -github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +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= @@ -410,6 +526,7 @@ github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DM 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= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -421,23 +538,21 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/supranational/blst v0.3.11-0.20230406105308-e9dfc5ee724b h1:u49mjRnygnB34h8OKbnNJFVUtWSKIKb1KukdV8bILUM= -github.com/supranational/blst v0.3.11-0.20230406105308-e9dfc5ee724b/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= +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= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= -github.com/tklauser/go-sysconf v0.3.5 h1:uu3Xl4nkLzQfXNsWn15rPc/HQCJKObbt1dKJeWp3vU4= -github.com/tklauser/go-sysconf v0.3.5/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI= -github.com/tklauser/numcpus v0.2.2 h1:oyhllyrScuYI6g+h/zUvNXNp1wy7x8qQy3t/piefldA= -github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZFu0T9wgjM= +github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= +github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= +github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= +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 v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= -github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa h1:5SqCsI/2Qya2bCzK15ozrqo2sZxkh0FHynJZOTVoV6Q= -github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa/go.mod h1:1CNUng3PtjQMtRzJO4FMXBQvkGtuYRxxiR9xMa7jMwI= +github.com/urfave/cli/v2 v2.24.1 h1:/QYYr7g0EhwXEML8jO+8OYt5trPnLHS0p3mrgExJ5NU= +github.com/urfave/cli/v2 v2.24.1/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc= 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= @@ -454,49 +569,98 @@ github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmv 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= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +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-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 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= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= -golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= +golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20230206171751-46f607a40771 h1:xP7rWLUr1e1n2xkK5YB4LI0hPEy3LJC6Wk+D4pGlOJg= -golang.org/x/exp v0.0.0-20230206171751-46f607a40771/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +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= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20230810033253-352e893a4cad h1:g0bG7Z4uG+OgH2QDODnjp6ggkk1bJDsINcuWmJN1iJU= +golang.org/x/exp v0.0.0-20230810033253-352e893a4cad/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 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.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= -golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= +golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= 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= +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= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 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= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= @@ -504,112 +668,237 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= 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= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +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.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= 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= +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= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +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= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +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-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220209214540-3681064d5158/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= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= -golang.org/x/sys v0.7.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 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +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.0.0-20220922220347-f3bd1da661af h1:Yx9k8YCG3dvF87UAn2tu2HQLf2dt/eR1bXxpLMWeH+Y= -golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/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/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= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +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.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= -golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= +golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= 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= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df h1:5Pf6pFKu98ODmgnpvkJ3kFUOQGGLIzLIkbzUHp47618= -golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +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= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +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= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -618,11 +907,13 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= 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.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +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= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -632,28 +923,35 @@ 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/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= 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/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= -gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= 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= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 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-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 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= +gotest.tools/v3 v3.5.0 h1:Ljk6PdHdOhAb5aDMWXjDLMMhph+BpztA4v1QdqEW2eY= +gotest.tools/v3 v3.5.0/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= diff --git a/graphql/graphiql.go b/graphql/graphiql.go index 576a0cbe95..823df0c641 100644 --- a/graphql/graphiql.go +++ b/graphql/graphiql.go @@ -23,9 +23,12 @@ package graphql import ( - "bytes" - "fmt" + "encoding/json" "net/http" + "path/filepath" + + "github.com/ethereum/go-ethereum/graphql/internal/graphiql" + "github.com/ethereum/go-ethereum/log" ) // GraphiQL is an in-browser IDE for exploring GraphiQL APIs. @@ -34,87 +37,52 @@ import ( // For more information, see https://github.com/graphql/graphiql. type GraphiQL struct{} -func respond(w http.ResponseWriter, body []byte, code int) { - w.Header().Set("Content-Type", "application/json; charset=utf-8") +func respOk(w http.ResponseWriter, body []byte, ctype string) { + w.Header().Set("Content-Type", ctype) w.Header().Set("X-Content-Type-Options", "nosniff") - w.WriteHeader(code) - _, _ = w.Write(body) + w.Write(body) } -func errorJSON(msg string) []byte { - buf := bytes.Buffer{} - fmt.Fprintf(&buf, `{"error": "%s"}`, msg) - return buf.Bytes() +func respErr(w http.ResponseWriter, msg string, code int) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(code) + errMsg, _ := json.Marshal(struct { + Error string + }{Error: msg}) + w.Write(errMsg) } func (h GraphiQL) ServeHTTP(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { - respond(w, errorJSON("only GET requests are supported"), http.StatusMethodNotAllowed) + respErr(w, "only GET allowed", http.StatusMethodNotAllowed) return } - w.Header().Set("Content-Type", "text/html") - w.Write(graphiql) + switch r.URL.Path { + case "/graphql/ui/graphiql.min.css": + data, err := graphiql.Assets.ReadFile(filepath.Base(r.URL.Path)) + if err != nil { + log.Warn("Error loading graphiql asset", "err", err) + respErr(w, "internal error", http.StatusInternalServerError) + return + } + respOk(w, data, "text/css") + case "/graphql/ui/graphiql.min.js", + "/graphql/ui/react.production.min.js", + "/graphql/ui/react-dom.production.min.js": + data, err := graphiql.Assets.ReadFile(filepath.Base(r.URL.Path)) + if err != nil { + log.Warn("Error loading graphiql asset", "err", err) + respErr(w, "internal error", http.StatusInternalServerError) + return + } + respOk(w, data, "application/javascript; charset=utf-8") + default: + data, err := graphiql.Assets.ReadFile("index.html") + if err != nil { + log.Warn("Error loading graphiql asset", "err", err) + respErr(w, "internal error", http.StatusInternalServerError) + return + } + respOk(w, data, "text/html") + } } - -var graphiql = []byte(` - - - - - - - - - - - -
Loading...
- - - -`) diff --git a/graphql/graphql.go b/graphql/graphql.go index 1ac439753d..6417fc9ed3 100644 --- a/graphql/graphql.go +++ b/graphql/graphql.go @@ -31,7 +31,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/consensus/misc" + "github.com/ethereum/go-ethereum/consensus/misc/eip1559" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth/filters" @@ -183,6 +183,31 @@ func (at *AccessTuple) StorageKeys(ctx context.Context) []common.Hash { return at.storageKeys } +// Withdrawal represents a withdrawal of value from the beacon chain +// by a validator. For details see EIP-4895. +type Withdrawal struct { + index uint64 + validator uint64 + address common.Address + amount uint64 +} + +func (w *Withdrawal) Index(ctx context.Context) hexutil.Uint64 { + return hexutil.Uint64(w.index) +} + +func (w *Withdrawal) Validator(ctx context.Context) hexutil.Uint64 { + return hexutil.Uint64(w.validator) +} + +func (w *Withdrawal) Address(ctx context.Context) common.Address { + return w.address +} + +func (w *Withdrawal) Amount(ctx context.Context) hexutil.Uint64 { + return hexutil.Uint64(w.amount) +} + // Transaction represents an Ethereum transaction. // backend and hash are mandatory; all others will be fetched when required. type Transaction struct { @@ -197,11 +222,11 @@ type Transaction struct { // resolve returns the internal transaction object, fetching it if needed. // It also returns the block the tx belongs to, unless it is a pending tx. -func (t *Transaction) resolve(ctx context.Context) (*types.Transaction, *Block, error) { +func (t *Transaction) resolve(ctx context.Context) (*types.Transaction, *Block) { t.mu.Lock() defer t.mu.Unlock() if t.tx != nil { - return t.tx, t.block, nil + return t.tx, t.block } // Try to return an already finalized transaction tx, blockHash, _, index, err := t.r.backend.GetTransaction(ctx, t.hash) @@ -214,58 +239,58 @@ func (t *Transaction) resolve(ctx context.Context) (*types.Transaction, *Block, hash: blockHash, } t.index = index - return t.tx, t.block, nil + return t.tx, t.block } // No finalized transaction, try to retrieve it from the pool t.tx = t.r.backend.GetPoolTransaction(t.hash) - return t.tx, nil, nil + return t.tx, nil } func (t *Transaction) Hash(ctx context.Context) common.Hash { return t.hash } -func (t *Transaction) InputData(ctx context.Context) (hexutil.Bytes, error) { - tx, _, err := t.resolve(ctx) - if err != nil || tx == nil { - return hexutil.Bytes{}, err +func (t *Transaction) InputData(ctx context.Context) hexutil.Bytes { + tx, _ := t.resolve(ctx) + if tx == nil { + return hexutil.Bytes{} } - return tx.Data(), nil + return tx.Data() } -func (t *Transaction) Gas(ctx context.Context) (hexutil.Uint64, error) { - tx, _, err := t.resolve(ctx) - if err != nil || tx == nil { - return 0, err +func (t *Transaction) Gas(ctx context.Context) hexutil.Uint64 { + tx, _ := t.resolve(ctx) + if tx == nil { + return 0 } - return hexutil.Uint64(tx.Gas()), nil + return hexutil.Uint64(tx.Gas()) } -func (t *Transaction) GasPrice(ctx context.Context) (hexutil.Big, error) { - tx, block, err := t.resolve(ctx) - if err != nil || tx == nil { - return hexutil.Big{}, err +func (t *Transaction) GasPrice(ctx context.Context) hexutil.Big { + tx, block := t.resolve(ctx) + if tx == nil { + return hexutil.Big{} } switch tx.Type() { case types.AccessListTxType: - return hexutil.Big(*tx.GasPrice()), nil + return hexutil.Big(*tx.GasPrice()) case types.DynamicFeeTxType: if block != nil { if baseFee, _ := block.BaseFeePerGas(ctx); baseFee != nil { - // price = min(tip, gasFeeCap - baseFee) + baseFee - return (hexutil.Big)(*math.BigMin(new(big.Int).Add(tx.GasTipCap(), baseFee.ToInt()), tx.GasFeeCap())), nil + // price = min(gasTipCap + baseFee, gasFeeCap) + return (hexutil.Big)(*math.BigMin(new(big.Int).Add(tx.GasTipCap(), baseFee.ToInt()), tx.GasFeeCap())) } } - return hexutil.Big(*tx.GasPrice()), nil + return hexutil.Big(*tx.GasPrice()) default: - return hexutil.Big(*tx.GasPrice()), nil + return hexutil.Big(*tx.GasPrice()) } } func (t *Transaction) EffectiveGasPrice(ctx context.Context) (*hexutil.Big, error) { - tx, block, err := t.resolve(ctx) - if err != nil || tx == nil { - return nil, err + tx, block := t.resolve(ctx) + if tx == nil { + return nil, nil } // Pending tx if block == nil { @@ -281,40 +306,40 @@ func (t *Transaction) EffectiveGasPrice(ctx context.Context) (*hexutil.Big, erro return (*hexutil.Big)(math.BigMin(new(big.Int).Add(tx.GasTipCap(), header.BaseFee), tx.GasFeeCap())), nil } -func (t *Transaction) MaxFeePerGas(ctx context.Context) (*hexutil.Big, error) { - tx, _, err := t.resolve(ctx) - if err != nil || tx == nil { - return nil, err +func (t *Transaction) MaxFeePerGas(ctx context.Context) *hexutil.Big { + tx, _ := t.resolve(ctx) + if tx == nil { + return nil } switch tx.Type() { case types.AccessListTxType: - return nil, nil + return nil case types.DynamicFeeTxType: - return (*hexutil.Big)(tx.GasFeeCap()), nil + return (*hexutil.Big)(tx.GasFeeCap()) default: - return nil, nil + return nil } } -func (t *Transaction) MaxPriorityFeePerGas(ctx context.Context) (*hexutil.Big, error) { - tx, _, err := t.resolve(ctx) - if err != nil || tx == nil { - return nil, err +func (t *Transaction) MaxPriorityFeePerGas(ctx context.Context) *hexutil.Big { + tx, _ := t.resolve(ctx) + if tx == nil { + return nil } switch tx.Type() { case types.AccessListTxType: - return nil, nil + return nil case types.DynamicFeeTxType: - return (*hexutil.Big)(tx.GasTipCap()), nil + return (*hexutil.Big)(tx.GasTipCap()) default: - return nil, nil + return nil } } func (t *Transaction) EffectiveTip(ctx context.Context) (*hexutil.Big, error) { - tx, block, err := t.resolve(ctx) - if err != nil || tx == nil { - return nil, err + tx, block := t.resolve(ctx) + if tx == nil { + return nil, nil } // Pending tx if block == nil { @@ -336,9 +361,9 @@ func (t *Transaction) EffectiveTip(ctx context.Context) (*hexutil.Big, error) { } func (t *Transaction) Value(ctx context.Context) (hexutil.Big, error) { - tx, _, err := t.resolve(ctx) - if err != nil || tx == nil { - return hexutil.Big{}, err + tx, _ := t.resolve(ctx) + if tx == nil { + return hexutil.Big{}, nil } if tx.Value() == nil { return hexutil.Big{}, fmt.Errorf("invalid transaction value %x", t.hash) @@ -346,34 +371,34 @@ func (t *Transaction) Value(ctx context.Context) (hexutil.Big, error) { return hexutil.Big(*tx.Value()), nil } -func (t *Transaction) Nonce(ctx context.Context) (hexutil.Uint64, error) { - tx, _, err := t.resolve(ctx) - if err != nil || tx == nil { - return 0, err +func (t *Transaction) Nonce(ctx context.Context) hexutil.Uint64 { + tx, _ := t.resolve(ctx) + if tx == nil { + return 0 } - return hexutil.Uint64(tx.Nonce()), nil + return hexutil.Uint64(tx.Nonce()) } -func (t *Transaction) To(ctx context.Context, args BlockNumberArgs) (*Account, error) { - tx, _, err := t.resolve(ctx) - if err != nil || tx == nil { - return nil, err +func (t *Transaction) To(ctx context.Context, args BlockNumberArgs) *Account { + tx, _ := t.resolve(ctx) + if tx == nil { + return nil } to := tx.To() if to == nil { - return nil, nil + return nil } return &Account{ r: t.r, address: *to, blockNrOrHash: args.NumberOrLatest(), - }, nil + } } -func (t *Transaction) From(ctx context.Context, args BlockNumberArgs) (*Account, error) { - tx, _, err := t.resolve(ctx) - if err != nil || tx == nil { - return nil, err +func (t *Transaction) From(ctx context.Context, args BlockNumberArgs) *Account { + tx, _ := t.resolve(ctx) + if tx == nil { + return nil } signer := types.LatestSigner(t.r.backend.ChainConfig()) from, _ := types.Sender(signer, tx) @@ -381,36 +406,27 @@ func (t *Transaction) From(ctx context.Context, args BlockNumberArgs) (*Account, r: t.r, address: from, blockNrOrHash: args.NumberOrLatest(), - }, nil + } } -func (t *Transaction) Block(ctx context.Context) (*Block, error) { - _, block, err := t.resolve(ctx) - if err != nil { - return nil, err - } - return block, nil +func (t *Transaction) Block(ctx context.Context) *Block { + _, block := t.resolve(ctx) + return block } -func (t *Transaction) Index(ctx context.Context) (*hexutil.Uint64, error) { - _, block, err := t.resolve(ctx) - if err != nil { - return nil, err - } +func (t *Transaction) Index(ctx context.Context) *hexutil.Uint64 { + _, block := t.resolve(ctx) // Pending tx if block == nil { - return nil, nil + return nil } index := hexutil.Uint64(t.index) - return &index, nil + return &index } // getReceipt returns the receipt associated with this transaction, if any. func (t *Transaction) getReceipt(ctx context.Context) (*types.Receipt, error) { - _, block, err := t.resolve(ctx) - if err != nil { - return nil, err - } + _, block := t.resolve(ctx) // Pending tx if block == nil { return nil, nil @@ -465,10 +481,7 @@ func (t *Transaction) CreatedContract(ctx context.Context, args BlockNumberArgs) } func (t *Transaction) Logs(ctx context.Context) (*[]*Log, error) { - _, block, err := t.resolve(ctx) - if err != nil { - return nil, err - } + _, block := t.resolve(ctx) // Pending tx if block == nil { return nil, nil @@ -504,19 +517,16 @@ func (t *Transaction) getLogs(ctx context.Context, hash common.Hash) (*[]*Log, e return &ret, nil } -func (t *Transaction) Type(ctx context.Context) (*hexutil.Uint64, error) { - tx, _, err := t.resolve(ctx) - if err != nil { - return nil, err - } +func (t *Transaction) Type(ctx context.Context) *hexutil.Uint64 { + tx, _ := t.resolve(ctx) txType := hexutil.Uint64(tx.Type()) - return &txType, nil + return &txType } -func (t *Transaction) AccessList(ctx context.Context) (*[]*AccessTuple, error) { - tx, _, err := t.resolve(ctx) - if err != nil || tx == nil { - return nil, err +func (t *Transaction) AccessList(ctx context.Context) *[]*AccessTuple { + tx, _ := t.resolve(ctx) + if tx == nil { + return nil } accessList := tx.AccessList() ret := make([]*AccessTuple, 0, len(accessList)) @@ -526,40 +536,50 @@ func (t *Transaction) AccessList(ctx context.Context) (*[]*AccessTuple, error) { storageKeys: al.StorageKeys, }) } + return &ret +} + +func (t *Transaction) R(ctx context.Context) hexutil.Big { + tx, _ := t.resolve(ctx) + if tx == nil { + return hexutil.Big{} + } + _, r, _ := tx.RawSignatureValues() + return hexutil.Big(*r) +} + +func (t *Transaction) S(ctx context.Context) hexutil.Big { + tx, _ := t.resolve(ctx) + if tx == nil { + return hexutil.Big{} + } + _, _, s := tx.RawSignatureValues() + return hexutil.Big(*s) +} + +func (t *Transaction) V(ctx context.Context) hexutil.Big { + tx, _ := t.resolve(ctx) + if tx == nil { + return hexutil.Big{} + } + v, _, _ := tx.RawSignatureValues() + return hexutil.Big(*v) +} + +func (t *Transaction) YParity(ctx context.Context) (*hexutil.Uint64, error) { + tx, _ := t.resolve(ctx) + if tx == nil || tx.Type() == types.LegacyTxType { + return nil, nil + } + v, _, _ := tx.RawSignatureValues() + ret := hexutil.Uint64(v.Int64()) return &ret, nil } -func (t *Transaction) R(ctx context.Context) (hexutil.Big, error) { - tx, _, err := t.resolve(ctx) - if err != nil || tx == nil { - return hexutil.Big{}, err - } - _, r, _ := tx.RawSignatureValues() - return hexutil.Big(*r), nil -} - -func (t *Transaction) S(ctx context.Context) (hexutil.Big, error) { - tx, _, err := t.resolve(ctx) - if err != nil || tx == nil { - return hexutil.Big{}, err - } - _, _, s := tx.RawSignatureValues() - return hexutil.Big(*s), nil -} - -func (t *Transaction) V(ctx context.Context) (hexutil.Big, error) { - tx, _, err := t.resolve(ctx) - if err != nil || tx == nil { - return hexutil.Big{}, err - } - v, _, _ := tx.RawSignatureValues() - return hexutil.Big(*v), nil -} - func (t *Transaction) Raw(ctx context.Context) (hexutil.Bytes, error) { - tx, _, err := t.resolve(ctx) - if err != nil || tx == nil { - return hexutil.Bytes{}, err + tx, _ := t.resolve(ctx) + if tx == nil { + return hexutil.Bytes{}, nil } return tx.MarshalBinary() } @@ -704,7 +724,7 @@ func (b *Block) NextBaseFeePerGas(ctx context.Context) (*hexutil.Big, error) { return nil, nil } } - nextBaseFee := misc.CalcBaseFee(chaincfg, header) + nextBaseFee := eip1559.CalcBaseFee(chaincfg, header) return (*hexutil.Big)(nextBaseFee), nil } @@ -966,6 +986,39 @@ func (b *Block) OmmerAt(ctx context.Context, args struct{ Index Long }) (*Block, }, nil } +func (b *Block) WithdrawalsRoot(ctx context.Context) (*common.Hash, error) { + header, err := b.resolveHeader(ctx) + if err != nil { + return nil, err + } + // Pre-shanghai blocks + if header.WithdrawalsHash == nil { + return nil, nil + } + return header.WithdrawalsHash, nil +} + +func (b *Block) Withdrawals(ctx context.Context) (*[]*Withdrawal, error) { + block, err := b.resolve(ctx) + if err != nil || block == nil { + return nil, err + } + // Pre-shanghai blocks + if block.Header().WithdrawalsHash == nil { + return nil, nil + } + ret := make([]*Withdrawal, 0, len(block.Withdrawals())) + for _, w := range block.Withdrawals() { + ret = append(ret, &Withdrawal{ + index: w.Index, + validator: w.Validator, + address: w.Address, + amount: w.Amount, + }) + } + return &ret, nil +} + // BlockFilterCriteria encapsulates criteria passed to a `logs` accessor inside // a block. type BlockFilterCriteria struct { @@ -1087,7 +1140,7 @@ func (b *Block) Call(ctx context.Context, args struct { func (b *Block) EstimateGas(ctx context.Context, args struct { Data ethapi.TransactionArgs }) (hexutil.Uint64, error) { - return ethapi.DoEstimateGas(ctx, b.r.backend, args.Data, *b.numberOrHash, b.r.backend.RPCGasCap()) + return ethapi.DoEstimateGas(ctx, b.r.backend, args.Data, *b.numberOrHash, nil, b.r.backend.RPCGasCap()) } type Pending struct { @@ -1151,7 +1204,7 @@ func (p *Pending) EstimateGas(ctx context.Context, args struct { Data ethapi.TransactionArgs }) (hexutil.Uint64, error) { latestBlockNr := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber) - return ethapi.DoEstimateGas(ctx, p.r.backend, args.Data, latestBlockNr, p.r.backend.RPCGasCap()) + return ethapi.DoEstimateGas(ctx, p.r.backend, args.Data, latestBlockNr, nil, p.r.backend.RPCGasCap()) } // Resolver is the top-level object in the GraphQL hierarchy. @@ -1164,6 +1217,9 @@ func (r *Resolver) Block(ctx context.Context, args struct { Number *Long Hash *common.Hash }) (*Block, error) { + if args.Number != nil && args.Hash != nil { + return nil, errors.New("only one of number or hash must be specified") + } var numberOrHash rpc.BlockNumberOrHash if args.Number != nil { if *args.Number < 0 { @@ -1207,7 +1263,7 @@ func (r *Resolver) Blocks(ctx context.Context, args struct { if to < from { return []*Block{}, nil } - ret := make([]*Block, 0, to-from+1) + var ret []*Block for i := from; i <= to; i++ { numberOrHash := rpc.BlockNumberOrHashWithNumber(i) block := &Block{ @@ -1225,6 +1281,9 @@ func (r *Resolver) Blocks(ctx context.Context, args struct { break } ret = append(ret, block) + if err := ctx.Err(); err != nil { + return nil, err + } } return ret, nil } @@ -1233,19 +1292,17 @@ func (r *Resolver) Pending(ctx context.Context) *Pending { return &Pending{r} } -func (r *Resolver) Transaction(ctx context.Context, args struct{ Hash common.Hash }) (*Transaction, error) { +func (r *Resolver) Transaction(ctx context.Context, args struct{ Hash common.Hash }) *Transaction { tx := &Transaction{ r: r, hash: args.Hash, } // Resolve the transaction; if it doesn't exist, return nil. - t, _, err := tx.resolve(ctx) - if err != nil { - return nil, err - } else if t == nil { - return nil, nil + t, _ := tx.resolve(ctx) + if t == nil { + return nil } - return tx, nil + return tx } func (r *Resolver) SendRawTransaction(ctx context.Context, args struct{ Data hexutil.Bytes }) (common.Hash, error) { diff --git a/graphql/graphql_test.go b/graphql/graphql_test.go index 0efee51a66..4bbfb7251d 100644 --- a/graphql/graphql_test.go +++ b/graphql/graphql_test.go @@ -28,6 +28,8 @@ 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/consensus/ethash" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" @@ -67,7 +69,7 @@ func TestGraphQLBlockSerialization(t *testing.T) { GasLimit: 11500000, Difficulty: big.NewInt(1048576), } - newGQLService(t, stack, genesis, 10, func(i int, gen *core.BlockGen) {}) + newGQLService(t, stack, false, genesis, 10, func(i int, gen *core.BlockGen) {}) // start node if err := stack.Start(); err != nil { t.Fatalf("could not start node: %v", err) @@ -191,7 +193,7 @@ func TestGraphQLBlockSerializationEIP2718(t *testing.T) { BaseFee: big.NewInt(params.InitialBaseFee), } signer := types.LatestSigner(genesis.Config) - newGQLService(t, stack, genesis, 1, func(i int, gen *core.BlockGen) { + newGQLService(t, stack, false, genesis, 1, func(i int, gen *core.BlockGen) { gen.SetCoinbase(common.Address{1}) tx, _ := types.SignNewTx(key, signer, &types.LegacyTx{ Nonce: uint64(0), @@ -292,7 +294,7 @@ func TestGraphQLConcurrentResolvers(t *testing.T) { defer stack.Close() var tx *types.Transaction - handler, chain := newGQLService(t, stack, genesis, 1, func(i int, gen *core.BlockGen) { + handler, chain := newGQLService(t, stack, false, genesis, 1, func(i int, gen *core.BlockGen) { tx, _ = types.SignNewTx(key, signer, &types.LegacyTx{To: &dad, Gas: 100000, GasPrice: big.NewInt(params.InitialBaseFee)}) gen.AddTx(tx) tx, _ = types.SignNewTx(key, signer, &types.LegacyTx{To: &dad, Nonce: 1, Gas: 100000, GasPrice: big.NewInt(params.InitialBaseFee)}) @@ -360,6 +362,66 @@ func TestGraphQLConcurrentResolvers(t *testing.T) { } } +func TestWithdrawals(t *testing.T) { + var ( + key, _ = crypto.GenerateKey() + addr = crypto.PubkeyToAddress(key.PublicKey) + + genesis = &core.Genesis{ + Config: params.AllEthashProtocolChanges, + GasLimit: 11500000, + Difficulty: common.Big1, + Alloc: core.GenesisAlloc{ + addr: {Balance: big.NewInt(params.Ether)}, + }, + } + signer = types.LatestSigner(genesis.Config) + stack = createNode(t) + ) + defer stack.Close() + + handler, _ := newGQLService(t, stack, true, genesis, 1, func(i int, gen *core.BlockGen) { + tx, _ := types.SignNewTx(key, signer, &types.LegacyTx{To: &common.Address{}, Gas: 100000, GasPrice: big.NewInt(params.InitialBaseFee)}) + gen.AddTx(tx) + gen.AddWithdrawal(&types.Withdrawal{ + Validator: 5, + Address: common.Address{}, + Amount: 10, + }) + }) + // start node + if err := stack.Start(); err != nil { + t.Fatalf("could not start node: %v", err) + } + + for i, tt := range []struct { + body string + want string + }{ + // Genesis block has no withdrawals. + { + body: "{block(number: 0) { withdrawalsRoot withdrawals { index } } }", + want: `{"block":{"withdrawalsRoot":null,"withdrawals":null}}`, + }, + { + body: "{block(number: 1) { withdrawalsRoot withdrawals { validator amount } } }", + want: `{"block":{"withdrawalsRoot":"0x8418fc1a48818928f6692f148e9b10e99a88edc093b095cb8ca97950284b553d","withdrawals":[{"validator":"0x5","amount":"0xa"}]}}`, + }, + } { + res := handler.Schema.Exec(context.Background(), tt.body, "", map[string]interface{}{}) + if res.Errors != nil { + t.Fatalf("failed to execute query for testcase #%d: %v", i, res.Errors) + } + have, err := json.Marshal(res.Data) + if err != nil { + t.Fatalf("failed to encode graphql response for testcase #%d: %s", i, err) + } + if string(have) != tt.want { + t.Errorf("response unmatch for testcase #%d.\nhave:\n%s\nwant:\n%s", i, have, tt.want) + } + } +} + func createNode(t *testing.T) *node.Node { stack, err := node.New(&node.Config{ HTTPHost: "127.0.0.1", @@ -374,16 +436,25 @@ func createNode(t *testing.T) *node.Node { return stack } -func newGQLService(t *testing.T, stack *node.Node, gspec *core.Genesis, genBlocks int, genfunc func(i int, gen *core.BlockGen)) (*handler, []*types.Block) { +func newGQLService(t *testing.T, stack *node.Node, shanghai bool, gspec *core.Genesis, genBlocks int, genfunc func(i int, gen *core.BlockGen)) (*handler, []*types.Block) { ethConf := ðconfig.Config{ - Genesis: gspec, - NetworkId: 1337, - TrieCleanCache: 5, - TrieCleanCacheJournal: "triecache", - TrieCleanCacheRejournal: 60 * time.Minute, - TrieDirtyCache: 5, - TrieTimeout: 60 * time.Minute, - SnapshotCache: 5, + Genesis: gspec, + NetworkId: 1337, + TrieCleanCache: 5, + TrieDirtyCache: 5, + TrieTimeout: 60 * time.Minute, + SnapshotCache: 5, + } + var engine consensus.Engine = ethash.NewFaker() + if shanghai { + engine = beacon.NewFaker() + chainCfg := gspec.Config + chainCfg.TerminalTotalDifficultyPassed = true + chainCfg.TerminalTotalDifficulty = common.Big0 + // GenerateChain will increment timestamps by 10. + // Shanghai upgrade at block 1. + shanghaiTime := uint64(5) + chainCfg.ShanghaiTime = &shanghaiTime } ethBackend, err := eth.New(stack, ethConf) if err != nil { @@ -391,7 +462,7 @@ func newGQLService(t *testing.T, stack *node.Node, gspec *core.Genesis, genBlock } // Create some blocks and import them chain, _ := core.GenerateChain(params.AllEthashProtocolChanges, ethBackend.BlockChain().Genesis(), - ethash.NewFaker(), ethBackend.ChainDb(), genBlocks, genfunc) + engine, ethBackend.ChainDb(), genBlocks, genfunc) _, err = ethBackend.BlockChain().InsertChain(chain) if err != nil { t.Fatalf("could not create import blocks: %v", err) diff --git a/graphql/internal/graphiql/build.go b/graphql/internal/graphiql/build.go new file mode 100644 index 0000000000..0065c1112f --- /dev/null +++ b/graphql/internal/graphiql/build.go @@ -0,0 +1,8 @@ +package graphiql + +import ( + "embed" +) + +//go:embed *.js *.css *.html +var Assets embed.FS diff --git a/graphql/internal/graphiql/graphiql.min.css b/graphql/internal/graphiql/graphiql.min.css new file mode 100644 index 0000000000..521452299c --- /dev/null +++ b/graphql/internal/graphiql/graphiql.min.css @@ -0,0 +1,337 @@ +@font-face { + font-family: Roboto; + font-style: italic; + font-weight: 400; + font-display: swap; + src: url(data:font/woff2;base64,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) + format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, + U+FE2E-FE2F; +} +@font-face { + font-family: Roboto; + font-style: italic; + font-weight: 400; + font-display: swap; + src: url(data:font/woff2;base64,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) + format('woff2'); + unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +@font-face { + font-family: Roboto; + font-style: italic; + font-weight: 400; + font-display: swap; + src: url(data:font/woff2;base64,d09GMgABAAAAAAMwAA4AAAAABZgAAALdAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGiYbIBw2BmAANBEMCoI4ghsLEAABNgIkAxwEIAWDCgcgG3YEyI7DdHsjE9IUV+CFDh74vPL9/MmgO0un0soqjWt7En2kQoCMtXsRxyxkMqP9iO6NfSiUaLJuoRIKnhI0+ImbcWOB5XOAFVmCgxZQQmuBJRhZtsUCXm/492Dyuk2YZJdkdApZeOzyEQgKOwDgRjASBEEBVmAlgACtOHEhpjLyyrACMAB0vaLa6cAw5bc5bvhA2uwO7zXAyKPmkYNnAJgBxLEMDxFLqVBPI6EQ/daTr/QOAgfCngRoZc4UZiL623qCkf/oHVsfRCOuAIbJyF4ajQQKQLmQhNBAA4aygH9b19Xw4iAC8DkKM6WrYw/ABMAOWEAamA7sgBWACgAUSlc3SCmlc95o45idYD92Qt/+5gF19v3FALtB9+7dq/h6/Ljyu/zzYfnngwdlHxO+k39nOcO/e7nPf2vCoo3HVlmNTdnWwW3JZffuVU6cQX14kb3qUGOOJ+mjP9iMeb1Nivq5gXpJUWm+cmVK56e6PjI2uce23hHlG48vyDvym5/5q+wbkjq90rN+z53D6zXqmVUPVshZoVtrZgc4vleS1NNrni6VR8I/vTrpzpPwu1+1Pel4xBIzK16W3KcLNnVGl2RGZHbPXBAvhw4M02Ci/t0BBfw/p79XS9V7CKAMF0++DK9rtI/7MXvGATjz0TEA4K4oef476t9dS555BAoLBYCA6ei/FSzVgvg/cIR45gpTaLWeLiB+oa4xJuTks7r7/xwCmCzlpoJKALCDQmkyEsCsN0mELUADghGsGgAF6c9IXkabDYyqg6WMkZd9z7BT5gaphhhqnOH66aOvkTQhggQLpsk0xBB9DNSLJttgPQTQJBtoIE0JEY2wb+1lhF6GG62XngKUGKLFECMNkW2kZgP10+M31GZUwfojwkU0uAcQkISKFNtqGMlau3vIjjRUjMANjYkDNKeouYh7CRBmuD4CHQgHG6GXET8oT7ZU6QqUStddiABBJPSv6P315AAA) + format('woff2'); + unicode-range: U+1F00-1FFF; +} +@font-face { + font-family: Roboto; + font-style: italic; + font-weight: 400; + font-display: swap; + src: url(data:font/woff2;base64,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) + format('woff2'); + unicode-range: U+0370-03FF; +} +@font-face { + font-family: Roboto; + font-style: italic; + font-weight: 400; + font-display: swap; + src: url(data:font/woff2;base64,d09GMgABAAAAAA8YAA4AAAAAIAwAAA7AAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGjQbhlocNgZgAIEAEQwKqgSlAAuCFgABNgIkA4QoBCAFgwoHIBt7G6OilpNWKhD8VYINh9o6+IoibkckFlELYovEnhpqEw5rTn/e1suwBSjaNcu4suz9n3jcWQcRrZXVPXCMsw+MIR+FMuwj40/HiI9xLIFVlPzc/Dy/zT/3XR5pAGb8ja8LKxcWukgzwYhaYGNU/ZQFxqLUVbuKhLd+MV/4m+w5Zhh/TqIcXmFFha2pbQiiNXT2bz+xUcQ2ClBzETSjEUCShW9ljKqw9VUk7wy62bj2txdropFFKSzBta/GGt+Y27eGWiiWyt7ti0gzFst8qOChQ0ge4e4Xlam50l6yu9/9571CniizBRTuQZii8rm9Jr3MJgXO5YHQ3fG/aiWhUC9UCdG2QoIRVa66XrCQtr6N6d8LoO2fUBohjoNU0/lfEUIVAcAkglGnCGlSg8wqhwgFeZAnQEDWpEUo2+9j5/Cu5Dy+i3cj9dodvLthT+/jQXc+j+9jQ4rqABCgQFVZgfgbAXENFhRCfbAhSLvJmn6RxTicVSDHB8Ca+Dznc0Prx37oR1d4uq/bnwjmW1rxklSRuTn+CMHl/qVl73Pmgos3js84a3+7n77Iq+1vE+1Fe3EhBXNMmbNkzZa9pZZz5IzPDdJur1AZsxYCloY5KVb4Id2f00SQWKZSyXIZxEFWb0ciZZweIg8biEPPNMhI8ZFLF97yWrRtwsAfKm+mqTSkjNRXIJrSEARYZDpddprdgvERSxcFBLCwysSIBqbLTaXhv2f1A0M8oA30gf5m+sC+2Pj79CaTVAsJ99HmgMzkreYnj7uutWi3UZCfeEK3Tp7cg4LQ/QaGwOPB9geMQt8AsFuWoEsXXiiY1jpMckLx8uE3sWE+MOLIUDHqk+R+m7xPvo7+098gHWLLQNHq1djde79LPpSvKM6AiH99Hmb+irlbd3fp3ZrbtzYPEtmzFO10pFtaeULsgC6LMEdY/2D3Brv7XjMJlrmHZcjjUJMYXcIDQaKhRP2xtyjW4vtCx/AR2IYtAaVikUCEbFqOgZggNHw9TiTV0zivDoHumy5YOohObF03tTrQ4VJlsBoLVDxVP/tDiqGrWr4E+6dyMcgcXBHwjcvr/Wio6T8/k2j3OHZ7eEDLUvDYK0qwnHYVzdyxP6a+hhg6UzcgxO0qdGIquQ71IHGYGYFAgyY689cq3+BFK+UiisgwhzE80guq+evJ7BabrUvK89hDJ6GjaKnXnHitv5Kiv71suv9EU0JXyUb011Rpa9fDLWF9SPrArCFyfg46z168k3t2zuGwtbZT1/xVsaOxlwjJ7KV+eFNfSxJie1oCtpsVqnixnwdz5u2z4oToO5UhpzRdZZMnPr1WRb0EyaYInb9lcHiuauG7pwjRQ8pZyD+89BCy7roasB0G/tFty5j8x3YGm069vWUZqwXisRsa+XTgOhfV/vxvhS0czgPe3oieIlQz2Spt5ypuqKo4fvp2+SIadwu6N9UfWxL75NKakCgf59Aidg4vWB9lT4ud57P8FGjmUT8XYDza6guZC2dpxRBWBi89oRP77VGElIrA6MCemtZEzOKmnqPApyu9WSAF3ksWM8OYQDxnfYS2X+7t9b9Ys+Bp6vl409pkS8dxps+CulHTNUbAluhid+nMSJBU6dB07+5VxIcfL+sJyb2PfcTKD8qEwLQYzAApmcHCQOhpnK38zNesrPt9GAWVoSAMu+fy1x3OO2aaIRnikpKp5Wq3s4dhKdEn8MNHNTpF8nOSHI2uvRsuCCB3X/1Hvhs2KFQQJzdlfCHbyWzHiD6tNK/OtKP4Iv6oTf+Ao82ctyoJgsYG2PdbyJmmKw24GJ9vKTHiPCYcyOmWm7V4D+WLusFvhQI4Q0qYoqt695xlHuBq4nxuxC12FVN0bYqZdp3dWv6/GLeQZyXqPUzRDQife3X1jsGFjkDF3SGGih4lJ+Fbc656cy7M77xWfXL+KZDGaxo0lg/jarRdQiti/KN64OEeYHkxQoOTg1Egqg6WXysFevCW+hMb4tEo3j0j1++jQlmjPMe+IPZG7d7Wa3i3yuAfaRwrnL7aVwBntBUGqxhnRPnEThy6KcpCyh6GIW7aJvFu3IS33aPuWyBVIqrjuqJQJzVn0Ou9fUMXjiX6SzzfwTuFY/i+HufuKnZvJ+NuyVZiGO+do48TDlQHpvs0p77olAj34NKGKB/nsEuJSOFUEjHcZdIhCyfyBcnDcH8na8ZuJ6/i3HETuX+C8BQK6oI/i9aVooM1gT/kmpS4XU2/XlZV4RJ0qMbvs0yj3EgL61X9bbdEqjMjI1ssIPyIluCo/XLptIB1rOwcsQCLiem7yuNwKrZw6zRux41z3Mm0XdL0vasNKW6rNzoTB8mYfrpIUcqasfsH+tmqCoZHDea9KqaeIxzc2PJND7xwvqdxsEMea+cfe0HjEzw2nd8D69PPTch6nhvipm2unCIr8P/T3G1GPJoPt7uacVpUcHxDzUmk3vw7apHGZ5xwVNhG1CV0RKIenNnv9c62liKv93C/g58BKSxXqCDObE39QHZQ4tWH9U7POCj2DBMPcHFrBCO1iLupF/RXajiqRVOiyZY11ZMG8j1Kzs3kdOPlRryX8pM3H3ELYY/c13SvAU9Tvhvp/eRsBYN566dxdtkq2Y3h3Pxa+YbsgQwdziq8inG4ypu1ZxCX4n1VPp/lG+fp/TS3HOmpzOpNwJWUo/fUjyZiF3p2RqUQJ+D/qv0/g7tQonUlUTZTzK1pBeVT5+b2M5PylRq67/zKbiGu4vdyapef4ZT2iv++xUZ85i+NTuaOh+D5oE52pK9rkGRE8P9Rjs3fOoM7cPNlxfFHkXaAFjv4Se9UKfanensobAYrlzdy9Sh5dGyklWArycbCyuxlVv7f9ZtwLqqvQ9n1QK3bjF3htCfLAbYe3mQl5hQHzT8tvWniSWjH51BZCfniQKRxJ8YB9XrrJMPszqtKraJYBsOR6dohF7OFEIcQG6hb+jRZbrCy4Ytc190n72O+u+0K/KiIVW+OhdVZCSOsM74QyW8m6hNRCKpDOHUrOuBrc137WvmqWW+Ykz5pekYdK+3a33Xesm7n2TdEM9hanBkr79zfedaVbEz2zG9C42AreNDYM3lzQgqW5MRIHnfroBdTNiaUcpcZmElNWU84zXd2WSnfKb8fDYOdVzsn1r3f/Owhkx/ou9QweWXoBT3+Oi7TJTDQgZexYsNbNmSFH7zNtT44OJ0MNr22MYW98XkoB9UmhYoRmbIJFamn7uNw8u6F0sJtv7mz3EPfs3A+Edau0g0Ws2N04UBKIcpFdemhNQin5yORRsaEDH19UKSr4ZZ1oS6EludGhdkfmsB5XhbfVteJ0POCy6ltu9WbdycW5sB32JZko3yQsWLh0qZc86629z4/JuEij7bwof4Ec7Nc+9j/DfgWeNz5AAQPAJCCHjJC1gRJGrSAAJ/X/10iV+QSC2CgmAY/shNMh18hpAxcEuTlkDmyMizaBN5AU5pQbgAoAIYAdiARDIJGShoMSeQxWJFRp4cxwdeBjsONlkrjsTQ6ARvSkCaEj+gkTIg6cTLs3NhmIIIHWendyzREcarpFFJBk7mYTilvX0aPuuKjdDq0tZROq0WjM6Ejvjyjjrwx87gCKTRmHpvvLyAVlnTBRHIj0yU05Bm505C+sHEfcu30+pcoAx1zQHbS2MFXOu6wVkrjJ2l0wkH9KU0ceUQn7Q2uc3L3nPoYNj8ip524AU+BdEC1QyneD1RqLObISfKS4gHDlGeJFUyTZgp4a7IBigCtM/T6WuFoyDDY8lgoyKTGGztjBKSlhZqWQ7Z4CdLSQlFakC2ehbS0YIsO2eJJSNs91GWj141Rl1UD5bxaJ49MgcqmtYiUzJ2L4rlz/tHQa8mRhkyHjfuBLDu9/lPKICd5HxhLMvsZ0flRQhzJBKAhf4irAiKEbaruhDCQE1KrDO0LmjsXm+bO+UtDryJ3GjKxP3A/oCtD7P03SJXc7RekRgQAYoAWxCXXGoEY4ATiiotU4D5ox5qmLCZw2ceZpxNf1W141usmAJD7RO/XO4hjwL5cedhoT84LX+UOMCu7GA7QX37Kk/bYuqtHQHsy2n7OFXBLa9WhyscvAnGs9ozYEsxRf87Mxm3FKYWPiyjd/d7peoekWgb2j//py51391nW3IoUXC377AfbJKxVYgBMbMPDbKX4y2H83DKdHy7F+qFQb20L5Nm+hx/Ut7PNEviUcmc2YoB3FrdniRGJi9OHSj5Pd4d7pt4uqZaJJzLOvZQ7t/ZT1kxHaj50xmDbhHWaI8AdoIfHXwZ6K1uQq1cPREr6Vj6Z7vsIr2osSx5dVjU6487j9hjTduP2JC6i9MjRZuu9NtUydJCXY3zVvig/GSnQdWOwTQLN5osL8KQ9jcaa4tQez29CO5EIamI/x7UHxxrXZjwSF/J0LSGgXHvsXis4xbZR8snSvk7474vX+QUPZxOTBBdjX8a1BYfAtad66hjFkcws6VAl8Iuxe23RlCkiqPde+TkMTzlOAAG68Hqx6cZAyHPJX1rtAoBPvxwjAH/k/vPN5uefzJorDUKGAhCk7v7LAJlhUeyvl7uB/CCaYVCaEfjA5D+48Y5lGvYdj5V9KFk9l6jcwWip6JYumbPjjHnGsjp58OMFK5kFPzcSUMY71OUwN/+yOj6y3AcvV5zl1CflL/sy98o2qRx/0fAObsL/j7jefYpoKPXinOv8PLcZL1/5eu7w5VSJcyrFPfVS8HI42lh7hvT4SIW1ZvqY02TfZc5sceQG4UPVry+jRS5e9K29zL7IkmpteFBt0qA9irCg2RoYb6YMQMBALWXeSAKgCKXjUAlIewyTZAA8Apws8h4Jip7LRldmUSs702p1X0bjN1p011kuJEmWI1WMKNHS6TJjwjTJ0+UmSQGJJ5x8pUQRjFZwLAjxy9wX8zRWF+bNQqkyh+ECRtwlCR+EdH0lrDDxC0dHlEfrjtx7GytNDHiiJsGo05w1e4WjrV3xxYy6p0tmxzgBWbqRaHyyMEvIiORUUYxtoUT1elpBX0OHcsa3jge+xSo+kwmM+AFiLIEIAAAA) + format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, + U+01AF-01B0, U+1EA0-1EF9, U+20AB; +} +@font-face { + font-family: Roboto; + font-style: italic; + font-weight: 400; + font-display: swap; + src: url(data:font/woff2;base64,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) + format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, + U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +@font-face { + font-family: Roboto; + font-style: italic; + font-weight: 400; + font-display: swap; + src: url(data:font/woff2;base64,d09GMgABAAAAADGMAA4AAAAAWyAAADEzAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGmQbmWQchV4GYACDIBEMCv886AILhAoAATYCJAOIEAQgBYMKByAbZ0wT7jBjHICxQe4g+S8SbPeQiQpRInToLKePPxGOhTMcUcL4M/miSRWxMQ1YOUKSWZ7/z7+e/7mrdp3u+0Bm/MjoDGRGpt8pxZHLvYbn7fbefze2G8ZKqC3aMhrEztjZK2etnazVJaeMJkVbQykpO+2tYW0Bl62mU0VMX3dfTn359t+MKSV06g8AV6TZHSVSI1PjNC6wZc8luVqHS8uBw/Hzu5fIXWkNH8JtcACzp/+/qe3bub47rGWvz9mHSGnIPlQuOlILR8vZpqKo3tw3Y8+bN+MwtkFCjrLPQSOTJBFsESXSmJRyaS1xN3tJ0VDFXKVYNOSip4OOugw/xgp/7TP3oeLulUYIYjlSvjK53y+tgxrbOz0opcYAAuIoRA5NXr/2b3etYBjuX453h6HY4CBIiyMoShQoSRIoRQooXTooSxYoRx6oVQfMqB8gCAMcBzgJBJQaYp6YY6y3De62tzewABsf1gr2BxsfdcrDD2x8fDk0AGwEH/eI4ADBjTIIAqjxuRNbN5CoJlyv4AB3NEWIJ6fzFBJSCeVkQbIsWYW8g1BLdCS6k1WIvsRQYjaxlnieOElWIy4QV8nRJAyaM8EYUj6plpxIGsBaN8nppBUTiSpkweVlyTumqyg1BRUBEmvSPxkEhe0/wQFHTzxmgCRRdf0p1slilsyuk3XnNd27nKl2+Vd56VTXBiD3FcgXykTj23mfhDT6x/WAzEsfBtKhp+0j438AFan7oDkeUyp53luqM+9buYIj6jSF8LFCe9jPiUS+CrcgfFg/kkP+zIVPlXtZavZfmTrxAGUV4fC/cnKXK5nPyyyLqA7rdG91sQovZDHT6v4+TmPO5E0asLBzNQv5gA6Ql1iR9+XNcT5IXZZSQos/kVMpyFnASZjJzdgih6cJZGMaEQ0TaO1qC7JqXmfl+n2LDmTZZfVCRL2GzTfPTsi9/VVy2Bd1RN5QW5Cj5q3gVk9jw0knlbSQsMkeEp6vBEA4NCMrdYdPNkTpwAdtA+pCxR7gFMbk+uHtfxbYyuV7WQuaEdMgVxyIZbQ/M7efkbd/wdmdeWs5xafyfPwJxAJIOyxjVp/acq51+Ku0eoBPeC9L4avD8lXN9boWyIzjLLHy81104RBQ0XBssMlmW2y13Q677bGXIiUqVB1w0CF69BkwZsqMOSvWbNlx4KRCpWo1Ro254qpxE6657oabbrntgSkPPTJt1rIVL6x66533Pvjok+9++OmX3yClTMNRIUgV2wHCZgmDOJG2AzPC2DK5DbGicPhBiSCtPKOT13Q30IMjYA6W1a2ywiav2GaVwybzfFmVoFbWkzEWK1fgKozDBFwznuWZ5zAH87AAi8ZSXluGFXgBq/AO3sMH+AifjM955Qt8hW/G96z6MQLZ5VJ7f5thrDEk5Tg8pUxRyRLVvHEgs2YhcQPgybcuTHKaShJcplmFzy7jjh3Ois1mSTGUnnxZOQGHTpA61uLIAhccAgJAg9eKYcHYZQQKeUc5wWN4AjPwtLEIAiaqpS6fTSerdAF6cAQsSb3M02EFpkqCaqgxlrJqGVbgBawaPzH9gt+NqXTyhi7owRGwhDxYgmVYgRewOndEnwBru9hhITD35TvAe/gAH+FTYzxmUrGhCmqhntyENxzwGJ7ADDxtTGVAmjGYVDdPoqMpZIfqnZXvAR/gI3yaPLIuo6zznl2eQ+hZoZ4vXNwQo593o/AVKGlhhIGSBfTSjNxBUOqPQ6tMs9aEXP6x9IrNrcCDaZCeS7JyUV3ugyrDA+mjg/aEGEGEJwOOZRCTYdhzRzbYAmebPciUHPTztegQowcmyaDpGqYsSLFismybrmPP0XrZTTepUGuz+jurYNSq7d76xNJ3v9nBKOpHERRBCZDgYJiNTMwmxrKZQVsYngKj2M6odjBhuxm0hwlSYnTKjEKFiVNlovYzpgOM5iAToMUItBmRjhJyD0mAk2ZKmhNDLFyiq/U4QOZgbA6MzFEx3AZiWElEFZRE0uKW1aolJECCp6bQmGsw1yfHcsNteA9Mgx57imJ2a0rzzCKCpaZClq0ieVuM884nKKUxsp9tIlgiC1kpQSxiwthKEFFFICmMHDGMghJBLoXZC4bZpxj4IQXJKIQcFEAqMomEeqAjpCBmiBCXQizBoKOMxsbF45eABEmKfnOSwuQSw+QVQ2XKCSOKLBREFgqmBF2GEgYkKAxLxJCMVCCmV0EUEXGs89k3eCS1sW5zdFcMwAAMuOlglIc/kXsMpP/POnsCuY/38XIB5RTWVm9/fEDYMcB7PNfNHwx8zgSDkSdzg8tPJ3OfQFGoUoN2PGddRP6kadcBVCHe6r5a0lD4Nj9bbKNv/7O6NHhztxlgEDO6lRWY2T0MZ1rc+0hjYUAhFU8ERORnwFTTFmuDyYhHgGREJAAg3Q9HpvdtEuoT+rP4EoK/wPPfwI7/gPzvLsYjIiFzcTce1+IeUJTQTt9VhOlYKdQNgrWNMRnWPz2dMO1ohcBFf/z1z38IwGcKQgyIk4SpRnPOeRKECBMhSqyzdA1BmEo4uYJbDJXLhyoO1gq8HIE9TCmKXj26ncRzSp/T+vFholEMiBYi1BlnDRoybAQEFcO484fxFwqDEbQGsGiEAqJpHnfBejq40AqF6yZCyhRHATvhRO878ZfbUqjeWspCQ60wpTo4zESbYQKCC0bNrUJ4YL1+7QbqQnp4fo+nzzQfn6XnAlcC7gK4COAO9zDWARDI3w38Ax65qx5AGnwLQN9y8UiThuTAVKchSDTDVe6PqztSg0cCHC9eg249LrjqjhXv/Yc7y3yMjKvjyXh6ESZ9JH2s9GnS4tJS0rLSG6V3S6tIaxZCC93bnSz73////89/cDxpDU7o0euicZNe+FA7y0zZOqdKi0pLbvUuaeV5V75liUwuE8olwHTUlLnZRuVw6O/EX/7/+39bMJfFX5LkuQTxYkQadw4Unn9/nvysBHbpBdW1t1R7W1vmE5Xvby+aZNT9ve0XnyzFY0/MeGpWqjTPPDdn3oJF6TL2vK+JTFk+++Krb77L9gOEIcHy34kA1QAw9gD4F3DCC4Fzb+uAvg4YfwSwVGo0Wx/CQ2AUowEbRLBQC5cqH3H2B3Rs80LAWiiLqaRi80HAKlijMPt0XGURP0cBAJspRFHokF1BLLBFI5DXrL9FyFuaKmFW+SjEJdHGT5jEvo/ZBL7rFnjILzyWll2tkQYWJenZ1WM1TnpCTpMG9JT/wfyJtRvv6XZEooquJm8nOdqrqbrSOgOjga2v3BZOzHjFChcYsK25VGaG87jpwORWWE7g95tVGgM/IReSV06lNLMgickRjRQtMmX648w5sc+nd0vC+5lxhRjLPjtLjszdi0+0xikYjDG94I4pgIkWHj0W1esh2UTHmEUuSC6UqelnGn5uOtXI1kEwvPbkgz8fOzOPTFdc8pRywVOnQaWAkdbOeOhiPUEHTAzuSGyS6IStZUaK4yJtKzRk4mVOGkPXLCcJYx5UsZXDLFKngaK1LrTPupjPipztRt6YCo9oUZ4jdLlKNc8dY5YzpECflyvHPPnhwC8zMeo1tryYQMeICx4GdviUlen9o2b6ipKBZ7lpemuknwZWDzTH/T4ZkgqXPXSrqjRG466WDKVd8NJOK+1ch2k4c+Gbj80j0521CgTLN7PfPXxq1EhvTaw2OeMa1XegWg6kxMdxJM/NZWs825J14iK1nKioS63WHES5S1Oh1D3VnVqmfJJelgXDTPBqEOQo61oV98mszcc1xkJe4bdCYJZIkx+fUpDw8GlmCrahmd43nUgIkuURGZYWkigyxwtts5aujBXLBAlpcVQZ21srAaNd1f8ZL5jMdS5+LW4cpVMsJHke8WWMnOKTFHI9lU2IVZuHcj1Q25N997duK5lRxiY5vGaVbxxzHRx6dlDCpZ5r+nWSrAwkK4NUMny6quLlvjPTM6fMaGnf2e7d+TzpkWRdEGzBucwESjkaSrg6DBN+eepbK7SSqaLGLBOV476CgX4/6dHDmgdSESz357kkLaGKnrJFtqpk/RzlZYSybs76cCA0SV0wHL4GCtiOnvvnk+GFXppzmyEQcPAbUgFmNK8qFLMvlAw3ye1R0MQzLahq4UuyVXnQCaSj7YcHN0M7ZLPjH9Xmcjjwo73XK9ZyeT3zza5svCUQOMoSuHxRRdqAuJhNXiITxGqCZrqxQnP7g1vg3NuOVuuvV8KAZ1+HyFpKqWWiRvjwLpatpEOQYd4s4TSTF1uOBnLarcE21slPtxRzAk2PE0sDzxyG6SloTmPTDoQ+BNccj9Am9tpSEgiR0pKZYa6yYZpRamENGngQjnrbrmEccxdTey86pVVUq6/Ap7nRHRWP7dKduCF784Em3IVfd84XXArItTWw1d7NbnlFNV2O9vWOHXMNL/DUXIAhcM8hvaDMfNNrkSknA95fi2lW2d8dtcv2V5Qe3W4TFGC8KHapIkV/fN4Z7EhIEEr22T86Ndeko1LTRTKyDASL+wwn75Aod3r8z8fO5Uema59IaIy+ofn39yIWb6XVOZdVPdQKQ65j7TCIdQqZWi7VNYxvldNJlQZ0JQT8HRjRmnV9XGjyeMM7gJQ9yZrfwLQd8GxT4ysZawcEoJDk6PRpjDVBSnTnl8TZO0efnba6CFjz5N4Lu/o4pnpgJsYYlKGS/vmdtj36YiiB3aCEqeOn5QL0L+81UnhdvCoovhKjtao36jh1GMZr0JjAeregp//Q/N4C8JlhzlHeE91DpYqQEGVg5aoy7lxjdWUP0c5YjYEgWW/Mp2qv7jdnKccNze2NVb5QpURarH9OIKE9idBRRwYjy4HkShZWqdkSHmhnUjFBdqGNOzDr7ClOg/PoOOVZ9YU/ta1OkXlOZ0g8PNAsI8OalT6u2ikutT3apm1mTNT7NtLAKaQ0ZUHJctsT6AqGAgGKoXwRYWFthZx1+YfxahuQUcsVnRqc+0ZEj6hE+miVbZPsv58RdJmdS5U8Eq+r3OpQJ4MMkCY7jPk5Mr0lnQVyTW2goz+Lqnhp1z58wxS0rIncwuW9lYgZjDHBfcmhRxsJZJhZcfwjDfxBT11lN+W5czM6h4LZOboDru7nYhnOKmuLi5oyZ1dOtFiWu3OLFxSvbTvKNg+LbeV5pJnluuVr3fcTU8h4Qz9SRiRmu9Ah2GvQp6d0Cmca12b+ohqIb0Y91kowe+loFyQXfF6C54/lMFi0X/z52Jl79OlvCb6ZqimivF/1+9yAgLiKsrXqbJria/OtE0WBVt7MWH64o+S9bK28cVkKP9fOBF59kg/VVe0QTdaOJk+XVz8vwr8ARTZyJrWUq8hLaR3GWbxb3BW7O6i4IGPZ2EHbvDWi/QN/uAWDKPJpkVzkjuLiile0XGwQaiptNr1rujl5iUirRsPTvEfbqd5cHcjtXjwQHpK+S2nJGxQxX10kLq+OiL/dcXn/0n1qFuXtTddf/O7LhaTmpdkqSheK24dPfaMaexDnuBdM3d7jttkU2JJlovQoom8yT3RJDtj7in6l1HQXhTFLAptK892ojBLnzCwip5V+Sb8Nw7ybZ2tTvLLbox2tiVJ1lDyCUeyYlXOUy4/9l7jDdx7ceRfRPUd/x7dfiFhUBOq2shM+JJfWlRcoVnuau5pqjMH47jrK2I4a1MdZi5K0UWaLqXcoRhErGD4tfOLVzUSeAXE/Ha97CXDMQx8mrz7czExQoQQmDMRZFnFz+NEIrJ8UlFMrofJGKzat17Orm4FyKTmQdLi5aFr9FTcNN8CWdlJJ4GWUtMJ2a/bXT66dqdnhJ4eLTzB67MyQMY4Cx/vouLYcltz69zIXZ6Sc8sywCsxyC+R4sxchSk4jAQGnC3gOvRc9bxJ772LUe0irmNdP8HnnlkAmWfwu9jGZVXST/OFGUS3bnIJGunjNgcx5O53TQbm3UqoQ5Zh3rav2BI2qe5A1gtEFswTPc2T1Pli8tOvqTpexfYXhYvFtCzbQ/QG4zQtBu7i34eYxgOeNIQ97gCeykrXC31MjFk8g6JAJHRDYUd1MKRU6LyFkxaj9eHdYYfuQA+oAomUBZnbHgPG3DNK7QpMMMP6alxxcrvpVVlVYWrUikvk/ofxDJJtdcbyo8vhvpRU7Yy3nWceZ7jsfp37ei3fL/kp0+QV2seLJlj4Jf5z195dE0kcpTQ8f8oQ3PineNFsiWfiBceE0sdiz1g0LhMXJ1ACSpX0Myz8vXK2K4ErrXLo7wpE5XyR7sUmk7SVlkE9JDq0Jg/GwMxVIT12NRPntxES8ASOtvyMWRcKiLmKcE61goPtwPM5E0/GjBnR3p5iQDAlH1D0OQ03o4UExeYKPQXmdxDj8YVpuf28CioDFHcREvAYt+1TPgXic8WFndagFXT2iyxoR9GdqQ7c/oYxpX1x19gl6u2oD7QTG4O2ioCNbDXRSiIHU5kcTTSgdnuwkxpO6buQXu/yItU0Xrj4h/q+qq/bLdd3AnoxJNAKX59oN0rCyEEZbT18MO5nhF5dHRE+J5kruvZWevsYUbydTc01zbiQQ8cg+4p1o8KwYpOpLr/Tx0Z7jRuIxtaFzkVEE+PuOr4q77TZuawjvCnE9dKJaAVld2c9n+sDWGkOJYCsYrCK/DB/guq8PKnC5htWYrhU6gzlTLYEomhG00SgQCtxlV651VMGPXa9iW8xOOJosMysS5AK2NtGzpXqzjG8MvOjbb6712gcASdZLPyRfIles/JRg+rpF8FlqRrx8BjTdBX+hyx8n9MT1gBrYFdusSJBvAo84Z9CZP8S3UI+ks+7TdkX6zqe4QTTwjfAK0yfpyL7ao0vdTjVPo0eCw7i/Fwg5uO5pmRdbZeghQBdHOk9IxXffWT8P7Afo7jeTM6ROSlyWBgPHhXJFyS7O7e2sfNoxbrYHSkYnG9g5fYCWln17ISAV60cP7jHamBdu3Lezvz9yAYijXREgtT+bFk4L4ab6wiBYn8kK6QPM08y5ETiAJp/S+0meOR0x+1w3uXQTQwTGRN9PoCE0+5zI6wd4bkRmEEpAHVXUREp4UmoiygZgb9HLMfHyURXTARXTVMHwXejF1R33x3lJN66BJ0/P3nso3qnCzTumlgD74SUa6w77uYjAJOqBUzP4gQ5CRFSKF0xAvecEqujpUb1hSBcGbo8Fqvw+gdp140jiveHLjAw+CoZN0QbT1GTOU0Gpa/gT6M4y4yLRW7pPM7Q8S0W5wBl2hMjbEA5DE7OdVS7G6iAS132OWU222VLmbAV0Wg7uDDt4dede0R8iFSPgcOoBkn9mb5iSw17bfqIv4+Ka1WtoBM3MM3opsVVDqcqGe/WbiA70s/jF86gH3XjMSjGhBkaUB6EYeLKBHk8NicwJgHHoZDVhnQzF3TvLGXFhVTEthOLlm+YM/WF1IdgdnKhn2GJgCoNhY5z+DDWJVpDx/klyCupBVz4Tb2K+EvXqYanRO/DyAjUbHiL26tQPW9QWsNeBqIuZoGrfNjcUg+udoJf7s+JO7nUGhIQ9f6SHHkeLFe29G73uJji4TmGrRIOc+6GtEsflwI57+ZaYNP93tFihEoxdNwHUKmnBTif9nEy0YwMEoqgOlmG2yAMmBzKtTwN285erPNiGzt6gNzP5Q21RXi7WwuXfDzFqP05eZygMz813AP0PgtbQ35pmkNGVj4VALp9aQ26oMJrhJcFsLNUjVZ6sLoFLd8aK8XxLCp1w2oe1ktOOPUVRf78sU4WJ/ccknheeAO2ow1Q8NNtq+TwQa61Suwen6y+LW3nzxrFLmHBbsfrN+WSnp/2nDuA6QzFfnH3pF0rqT1XnbNxFEZk3QOlurNHVmGs7w3gtbDxv8JDY88hWoCowxesEz2fH6X2syS8+Lhucz5ACGGNrVhbH222pm0HmmSJGDD3sWEoYkqtmgITeJEYQzcffLw63BgA91uSWeU3iAj4duxbPfYcvRKYUQ2aEgk5ANAF3E70HhMVh2s4FETiC+yO7/rdQOf4o/kz+dC6qwF2t2d1twFMQBfrAKa6S8CWyrtyBsujdsIxNcw87Cx5sJMoty56hJDKqT/aWIHAAO+FugyYkalPOnItE3TmT++5ANTjFhJs84mr+Lyie5UdToMO7qOspHNAH87GphKh3pApCuG4ZfxOz5iR2HX1YZd4bomQVlMSjYcIfiU1Mdg525MqJh0XwHi7GX1VbV6IGgOiR0IbxF0keGPEPuorBcwA33BgYBkrL7hNB+UKUvMX5cgtdQHefU0eHKRHcfC6MRh0n2IlgbeOD8+aLwpOIGVse+9ScI2m+/i5g19ZL1NoO5ngOyFryBL40bhlr/K50Xm6HwvW2aGYXMjVP2IQ4bzu7CogekE71pWn6nmtwfimWcmkW3GFgwsnGbiaE/cBX4yPV3U6sCbGsDZlAD9BXKdIX5L1LI1nI3eFkE3OxAj9WNl2C0tC9inQF1gtMDT9aMVuIRnA/xDf/r3HARtlVWdOLYRnMf37HvMKa3Pz+88E6DVA1WsXMFIhOq0xA1gAo8QymJ7MD/37SE9DPBHeSg7/ha/BxavZ1olzL41G3UC52JynI/7iYOdmManGg1zuWMF4xVTT0UqLgA+PpXi7YGcIvkS3/BONBt4GJh8G43ux8sATeL7OvUDJ5d4r3zHvSJsBLDii8UslMYMQm5aUiWQAU70YIHR/W6z5YuS6V/YEcWTT4wT0DS8Fuc/0m8HEjgJyWU5wEM+GZFHoQp/S6Qeke/bViSYL/XXRB3zeXPCwTLASHjRPihwEpqb5SBg0nAaMp9hWGEHtYfmt2RaJOC5jheZSUxzILGrQllI/di3Z7xsyjpDwZpITMMCuzenNQBX6SJ36ckvIUHADrv5x8sB3Pa2WH8a6AcxfRSY0uid2fjxP3AHLLwQkRjdlL61p4XcQleeS2JWQNbk0XcQPvDNjSlNK+bVXxidmD+1CRr7h6eEVvYhK4Tr17PLf5fo294LDTFkHz9JvgZa2sRC1evGq/e+QXibonYuVgc8vqINMqc0ikgsvRORsIqF95zZwB+SZA+ZYYyDl6NlCkYphplTkCpMcGqc9PNTyMbXxYD36VR4uXRwPZ/if5NzfcAnx/yc2lWa0oH/bxiKnkLtGLyyOAakl2dgx0hPYw31HAkA9IjknFN0z8YTsaHmM0HhXBGQhPMe/nWMFqq30GG59lgi6+H9WVdMTaHRwyE+W05JGvJURjo8gxf31cG3MA8P0PJBUMohrUM4u7LODXY44VeVX7onYU2mPyULW5Gfmg+jTTD+BFkjOsCRVx7AQMj9S2aw4+WDocyjz6hV6pzq4p+PoiMwd1oBszHe0A+gQlO6NcbOiR8KUtTkiDEBqWAcykOM155DspsVg/ck7w2sNntoIWdkhCzjAqQ6cWCOe38oWwfL86L1hLiGq2/KxaUod8scZ0i0/gE+caWpRhzeszG2rJ8+nJWCs6N0UawNQIahSzUVZx6q0UdBxllHgd1XB5GAA5t7hYa92OGjo4JBAX2AoiKBpdbaL5rawEsUY3O2+nRrjbkClU/hM6hobSnQV850Tz5yi7u4C5lAgvH3czNgobRk5Z6yJbqZrrJG8L/biBPwYn3JStPANcChtQIuqrkMzhOKWk8JA7VuppehlFiA9wsHzvWh90AoU2WnxQLanFF6OR78x7QIQzkFd9FlXA4pvss2Fj/PBxEz1mTgnWgiJOkdxwfOYA4IPFfuqYSv/G7LvXdzC6HNAgdKgDYu4qtAfDnMrm46lQXZ0lUKJ7N0msivZlWEqCkffx7k0FxvD8pWHQ+Ckv/lCIrB9CCioP4CY4vf5w09L/KljsZ7YCPhDVVBWOzCi4iDxhvo24acWp2+gEqrrL4YVf7Q+bMLdlZ9RjrrAhXtgz+vZAxDgtwD7CBbYjtzpSiQifOqYCRN1VxTKLjg+iSlR0YxwrN2LRPNHztb8p1SgDXiqw/8MoE2LXlf17m5eH0uHlApvvtFJGWwX1XfFznQCCBjksMscds8EqHL0uMEKJdkbUyKgcd5SDjc4LD4BDu0Q5zVnEG8kx2DByi3Ym85laT5oAJzKtYMhHp8COjzMvDqj2RrUoqNKWsL+gDqVjI9NgfanxAHKKlz7WFnvq+l1QUkwXqoD8ecIFfIwWO/vmOY/bOjhzrDCgwQtWorAyB456dhnKxIYfgW2ozILU61ZLMofu/LL1AvG44PIaJGMERtYzuFnyw4pvTYnnCPnfBlphE7w5hMpOA2ji43EUOkCN7W/IujSHhK22ooPba6rwQXj3iLJxo0CsCz4fQ9X9wC7kmIcrLLACa6fU5PFXRPPHAhu2CBEMjWR86OVqLA0/6FdNTT5Wd0E0/4I8HtzyjU8eRdWodIp9NmSIH3ruyBaczhFTDewS3qeRlCJo5L/Qu0DbH1G3AxdkBVWy6ZoqfeDgCSBUojIs9UClhIh2ibrtKiFaqPTg1m0URRuLwfuTG7KenVpLFLvSV7KjZPa83P9wFTQyRTlbJjavf5dGuIup6TAFypYsUazFdke1GGr/unPgZbmzePlh0cJt5sy9EpWSIjlg1r9uT8k7dpfEbRM9ZkYxUaBwmrz2ldSiipmju3jofa1tFJn30uOnHDwNyHlyKlKfoLYUsz5tD+ijFzNXzheDkF/T2luZUvNSdy7bB2rSipUNpL5CbexMqfK2wJo9Be/YneJ3THUF0ouJjMLH5LVvJW7vcvHxAob3KfTGy9M5MA6L5g7qHD6cgcm1htZgAicuT+aicMzP3tpMY/+hI97HWB6gr6uFUip4Xvyr8fY6J9QjL9A5P3kNrCY5w9pgcecuIJg2OXJ8jfwqX+F1+JrCYXouNUCOEnl3MDVccNs8f9tc8tri62WdvtwUZ1SBv/KfvkjG8kJqwZljEvc5lUc9r2OSta8law7DwM2ST8VvNYjX1kr9Eb0h9PUCvg1dmCTyhgDBxyXKHR1DVU0CiWt/KYrXgoNqAUNp59BVlBFXm+FfUJ+2xoJsxS6zlvYKDa3NjQ8q6Yvio2GYGd5bEVDUXbzWimrNKjARc40ILsuP37kQzAjSu1Mf7YdC0cO4wlmBaHqw7q26SD8Uhh7FFcwA2RTx2rInc3d+CMWqSDarCsWo7FM/p6S+Vyhmj2SzqhqLW7kzAUh0UpPIAP9eoaRMDKR8HQAaH8+wzt9z8vSktdN71t6YhdPo4zLlaj/AWxyMS9I8CsxgyV47V5Im1cA3QNDaeMPHYM5r+pm7nq4+tBaiX1p3uEL09lx4G80tUa/0E+NSymJQOhwIZXhTTJz8GebaUrSQ14Sq3a0KQuV0N/39otBETbRnt1AxRdeRG74F0Fts6HvrOc/PdTRso9fNfxgS2D40Z28+TTNLevlgaykqRMcf0VvJLpyR209qYR6qbsSX5AO8haaLDXSE8YWS/+hsgoGRjQbWQZA9f09M6DYinINDyODZQCznnNDN//AibgQZPOdH2G4Qurro5nD9EjoFJUbzbAVHha8vuhwdHwaUASTSfK2BsPNIz84y2CciGjnjggdj2gJA2lYRgpEFFmi140UNheJ/Mj4ZRqPUUnLMXltlWpxm1BFbDYl8h6OY16FwfQew71TEgAIxRLJhEwi7q/GOe6H4+WJboQnhG8uuttcuoL7MvTtySJGnJifO3AyLw4aQ3sxpFPsyPTXx0fUQaGf/3T01EjsSsMc0m2RuCkA2rjSRELRFw8lE3kCO5EyjWEltZ2ZbcAg6lgT17ZoaqCQxH+hAd82serUD1lguUNISzhPOzwOMsTMooKHBEzrD+FLojrj1NR7QBSYXxnqa7NfdqWhhfNRpn9EeRSsLsGXRykWk3FmtrlmtLly0PEyttoko+FlOpEIOnKjW5oS4bnE1p+pxtT6oA2P92SpACe0pTYARMDsO50GMLo/9NFoYA4RCPQ2BOrTf72EyuStQ0r6W4l4fGReH5YXhnAnhFephW1EiLqA/MRWGw9IY/4pd6ooqaraH3GkeuTgrACS+gRc7NxwHYksqnlyy+RbyQBE2gHeuJZ2WGaCOqTSygwOyTsAMY33rqX6m1hMgaEv8cA+b+8eZoOeVPH4fWigIBK7wQPMU2K/G+vh3F/gHL6mpgDbtREmUhnn0BJVhyK8FL+BO1faiTsmngtfV1V4WM/tE0t0ChcD6qSu5qGGMVknQZrZMTpShPNQwTisjaDHb7o3rnyE76QQbQCOMG8TwIpkQPfT8daAp5IbQ3YBOO9XfrMHbzdk2PJgWTHNxCLGHLjA1kOVwGrBbP1/noW507hqjhTFwvjfEw9ZCtPTroe098x975BlDdycngF8gsFFwlsQ5r2pt4DWKV9QffHhQvHyfNrvHSCay3+ku2GQabYQzTgjCG0YauidHGOPt/wEJxtHGwFCwBYUax1RXjLzw6cQtA+cdcuHYqbPzzvHYLZQYldxcfuf/jhByFL3dcnj+YL06V+H4P+gnZbbNLdfAqwbHx/3myH2WubCrSAcZUgzldofrKQeh87g/GzbRhYqBFJ+3a/1bcAe8XmAMU5Jyx976FgkDRaUBgSme94ijDAA5lyqZ8fSIxLwwBO7zqUtHWWlhtwZ9ImE96jlFKyE5nvhMPZK+16+oRDlQjtz0YqgbnYJBuiqVPvqB0CPblWLprehbXLY/3FF/n7OarZJjFNn0iJ8J8sYyygULgQ4QjIRn7XdZtJ/hoCLY3k3OJR//e/rxPKBaUr0sI22QFyzwZVj2sQXKf58chP6w0UrG4ET7JRQPe+L0njKzWGHnSRoFNN/EWC9gA2tV9RT2ZGZFHOSVacF6XXWlrW+vg8iWQKotSc/GSvX03mNYR+2eOopTugvF2MMOKC9zeBt3BtNsRVpryXOpSdgwes5mT9ALsj7NZqSgKhQQgPg+le9KVPxux3lYntqtVTuzryxjMknZf2ViX1wHrgCNXme3M7IThrhYPI7/ROoCUFuwvi595pqI4k5P3e1bFzST+x9wtL+Pw02wacnEE9pu9ShNAQW3jyURrggTLdk19YT3GXnQGtrL/voWyr0ZFkO4KWm3dh1h766TpeSUXbbXB/0/1qJJthUb05PSHD8tnJSDTcxIDdEcwaHLopyWHPL1xBhsELnHOJP5Qvsa+n0UkzP7UR3qXsRGaIMHcOZF3BoveBxxK2wI+/NrcZnYyBOwuOF4qHzgJQ22TbM0QQV6UufMEqxX2LqVZa33CerBe2zl6/g/0SVq3WzQhDYQPYJl0eiChX5Mp174+pP0fQU5siHBkJycVw42LRlFwnMhW11PPZ3GYuHJOL0ZZgY7qj/WiewXmuiEdeELAvbHa6iNqwfDGDgSKOfYOf0ZnwqH8yx+CJSuXYfbtrtW9xjSwIUG57tjGbjLM2JDQjirguAmf5SDu7gi3K8lU+GONVcplv8FR0KdaUaetkBR8wOjGAa2n2yrxJhCdF/A3BsJbRPjbMyCQyyhdWKMjUVwkIvFAUc5BSNtU4d96lsVjHWByvIsNSAqzWHDbf7sDgtMyj+KQD0Wm2MPJeZ81GCD1dpAIC7McdPj5oiniaT1s7jrZgHjgbCbXlixSJZwch87ct0cwIm76gcXiGSzfPgMJ9kZgOS99EPKxcvXdPaL1mz84FHu2ZpZJVYC/MfqPWj4g3cIDbQy9fa3FsPbBB6zNfP0sQQUiVPJcXPJHNvUSsBy4xsQLNGp4KUCE67LH8v8w88Z2LWwJpikR9CmRqSlBWGOWIwMriFIMhzOo7d71349DYRiukUze4RiWw7QVMRfQJuSNTJNPutcYQO8d03+UrRQbKhIZhjQaGFfjtqpVahdYOMg6quZezc3yEHUumw833jcxmi8gG4SCQ645siJl8sBO8rurlbR/BZAdxMfiHALduyF2jBVVktEri5wVwBcQjKLNKtHovkPV12lFL7AAaD81SNRSNUtIoDhyAqev+Zq5d+YLT5erPXRYAv0h2e2OHEElqf5V21PDTNSuO3+hePQVF9AqOIntAn1YTqwI1Po7mK8lYl+qAMzN2iIKFQH7wqAi1BmnmY1LZr/SL4pkOJxg1hFGE3aSiX5UQ4ehnlQXepS12y2Cz0m4Mn0S2X4ip6eutgBLWGg0PlNZiQF9rqnt7v/JpRZoDvOi+U/l1wI1NPNVD/f+XgKRu+offio8nif3ka7dP3E1vKywuPZMP4Gu0ROOWGPk72qrZqCncE12+ud1/VP43A4sLWeOkK2F9ZoVKa6o7XUJJR4mlpJi2L3dJ/JtLxq/d/Z6Insjs7Tu3egGFcsFZMc5fQRULw7loKXnGDzweL1zDyastVbOMlrTXv16xfYj8Y9/7v5/MtJZVkHoJUWln9fJMVEpfP34WOJqSgYH9NTnQxDYWECzrUEkNwDoLqlKVHDTk2Lp/ESrBtdS0um/sUs50wNPaBvWDHeDx91sv43Kuqi5OgI3SC9fXC1yB7uN9lJ0FZ2ireysvdW1QMNvDFez1hxn3CSLQjWJwRm6PqpoDDMuzEhFmPGYQXhOBdCUo2urSLyRr6NsREwBGaGj55TU1dUPGhxyM2U/v5rqaaQpWexQ1FX1dE2VGGX4X5w6ZDBIVu/qDx8ID66ty0JxsNUHqVgl9BdMPdgBy0+o9rh6AkTtF8/bts2Iy/5AxZ2BHU7lSNAw+PATssDF3ZuEL0sXhEHbIKrhsXLhwPi//i85LqqEPX56P/qST5j/tsvAFyB/Q8AdtgKZohNBJEZAuZx3ez4f/6Fx0sl/xzWcDyo3lBOgCv1MBqVFJ4oFtKI8cZF04tZoT6gx2m57kmor1yDN8WAeZ3UNGpoa/k5MPiWWkzupcDzkWq6WcUeGBWlDNRVHjdUWXvZrLV2Zbq62Z6dB4GhDZ6QUQO9UKnz9FN6n35a70d+SADi/wG8kiQgEHovq7GGxhU2aNpZs3xKkZMYVp8T8/3coLAgVDmpb+3uNgoqvtRxkxFVl/Pd36Klf18dJolhdSkx33jctyDKJ2rmXWKYiMT8xMd9c9bfZSvu9Xdb0J9dSiQxbAgm5pf4BoUlW/vTvmXR7Ssr6ncvRZIYVu8S832J+5aCf6A3nvO0yLAZgAho8wBnQ+RxbLzwaTih8qhaxIwCH1B9HazxoK+nAS/qeqg/TS9yz864r2zM6dd8Y9iGsMsFyt3bQgQoT45nZmPNY31zzXhNN/fNiQD/PiyJ4UNsK7DEt1GCt3QbPDrNxn9AJQSxwnfoi1LoUOv7wMwGqCgkYCUKowiKamKaOvHTULJuDSmYGNM63nITALbrLgLo8J7cxf5k6q7Np2pu7dQcZmFea7NRMfPnaQIqp9XkGwTW9atHv4bnQP3Er1zntI2cLpuyqrfYejg1A71zHtw4ylp4Cm0A3CKf2tx9bqNmrCyewpE5vkS5B5XJHlnomFgaXTSyx8w6q3EUmxufrviRO16vYR2jYLxaQ3yzMj+tPupZbcU1oQOYjT9DbKwdAthATgL9ip0i6K/TXxF/z06m9xXbX/j8FAs9HO6f6xpVoN+3Owy7JAM9YJwNgtg8n3j67+XRyudFFVjP2smIyItFJyqRaetWJvwHj5oN6Z3imO2vdmBdh8LdWZ13NgAzmtrCi8us173f1njX/O1pHw7PlTajlVdzbgNE/7DMnBkpVADqK+s/NIxv6K+t9pF11Vqgz1qvcRlWe+0GgPoIYOPsZkNqAxwbSstBa76xwIwYnS1TWXP8arNG60YCWS1cNhpnAn2t2uMiTxLvjT1/8QTnRftibGpWmobvY7kyVn9NKM2/5kDG4oVxaF0DAePSUw79mNjvlNv/d5LYHgB88U8sBQD4UZn95pfS3ymywT4EhgwDUMDu8QcaAEdncOyf/1kB/IDjHqpROXeO94/PJ3UcAY2RZqLvMmtP+mvQcM9SKXed45Rj41wKpiu/DmRQhSkYCsSGkL3zQAoi0hvwE0RgD+AhGAKhDtSrldZrctWbmvnHkwbj+ydKZfZr2WFAc4nnZD+nukSELhmqHULSgtYyF7WKKS3mtRlKv0javtptkrqKlrOIfk9PLbfvUukWm7pL+2Lz6l+atzdG+0Ue9GntfTKvh1j+T2UXtqmJnrqMZ3aSRqDJ1rC7Paxtcdrt60hvpDVGhPrzxrWJtfXG9lqK4PxJms3bHpFqs8hURtBqjzzqEHqj09qmAIVRQqNN2c2bAtZziXMxY3MgLUm+Xcsq1TsySCZ3wfGxf5PmY+sy69x8XsXYvYZGreR738zs1PVkW8d1JhudvWzaStK2nsus9H18sNrbbRgL7MeCgBFlqrlZnlNiBlNLfcvEWPBsFrk4ewisQYObAOjfOOrnQO7vjiS15W1ezqS7gVK3kdoqcLqcfUfSbC7lTslcfaWwC2SxE6YzT5XIaCyITpud/4F6C1ADAFiXaNvEVFWF3qqQVWWpHBMGxh1lYyClo03DUqU8HDkNR9gsyvuxwK09mfayVx2lq61Yd7DQrfOzAGB/o4vteYkYP21NLL+1DzHCIAXbgQqKUAhukAVF0AjxIx3tyTcUCynAdXrrCHsK48w6hBV++/tJ4ShCsYVYUAbNYVgZZmHzohCkMNtfQmFHIVdGCPsyaAm3ijCLKTsKNQJau7SmaTkqr838aKmdz1JD6bMRCwLVoJAwK3gQwAnAgJ2DAAL2PCGwyQB4IMCuB9E4Aqb7roeIC984bj28jQolYaQP3F8GC5M0cAWKEsyHF2+hpO2yw86nIU0Hl4P582isJ4AbBanugn+bmaAK4UgPHXoIFs4pdwpuistVIFTq0dW78OfDrWu8dKusVKRC+EAF2AMKO++2j6p14/dVm5Qnkh8qkIrtT4yQCgvxQC4pDwq0XjAv29MeAiyXIa40oHwNWoyYKyVvgdrxD7Dw5dx8uTsCAAAA) + format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, + U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, + U+FEFF, U+FFFD; +} +@font-face { + font-family: Roboto; + font-style: italic; + font-weight: 500; + font-display: swap; + src: url(data:font/woff2;base64,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) + format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, + U+FE2E-FE2F; +} +@font-face { + font-family: Roboto; + font-style: italic; + font-weight: 500; + font-display: swap; + src: url(data:font/woff2;base64,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) + format('woff2'); + unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +@font-face { + font-family: Roboto; + font-style: italic; + font-weight: 500; + font-display: swap; + src: url(data:font/woff2;base64,d09GMgABAAAAAANUAA4AAAAABbwAAAMBAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGiYbIBw2BmAANBEMCoI0ghgLEAABNgIkAxwEIAWDMgcgG5sECK4GbGM62A+KOMNGmZWUwcdhKI9l4Sh/WwYP/3af9w0W4ERa2bOg405uoSptTooGKkF8HniO5b+Iojvye4dReBbNtVHwcLQTG2gBzQfYOqjJ/XYU/jItwgxa4I3czM4Fj9LAAnlHz+dzgSO71Jqn2QML8H66dROj0qAFLYnRhtm0b89/erW/v8l/LA6we9gCizDBtQzSf4EtkcwDT6RtmgYEQXnDKGQslZyX/CkQSFgBAE4ERggEAgmwACwQgADMsONAJKVkFWEBgAJgwMz1NlLWec3G+jtZu+rXO1i7rx/sZi0AEwB5WVY28FUE1CORQAjvtSPftAwCQQjGAbTUfm4qwrvbNmDEf5pjR4JoxElAiYiMWjQyIAEy4EBGAA4UNKCgIMC7a5Cej2sCAA+SMEEyYA2AMQBWgCmQAObACrAAQAUAJCSDMEDmo7CztfXoRGu7SUeVdbvosOq6N6PHnZ2yf9l3eXPj/q2qXdkjBL+qrix1cYsqzItOvXfRPaMXkUvPeFWoxr7tZB8gfxIhMauBapmSUhO8d3O8wUt0MoI7UAxLzt0/zhCwJnVHrsPYXenm8suPeLYORWqn/3wwK6Qp+frDiYGvxHSXFzoXfpihfmlODl9oFbOqKa8nXbZgd6axNivh4JS8xEZKChij/nuDBPx/MrxQA/WBACCtK44947xa66g/k0YcALjxaesDuBuQP/7x/3bTwmQACVMkAAQYd/7HYBqK1H97hriqWIzlN7cD8Qu1mY6Ql7eR9v8qAcCY/apKqAgArEBCCmOEAExoJiOUENTgBAI3NSBhwSjIbLboV0Blo3PIiN06hxVFfmrr0WtMvzYtWg3SBPDjz58mVY8eLTrpNOm6NfKhidepk6ZAbgbym+oG6PoN0zXxUaBHgx6Demiy6Zq0GdIl3aB6ndo04r7WvSV0/Qa0Nd2+yKcNFCrSvh/6dNKO3xV33aBeEXxNZKTyQUaverfOR49+LZno1XUboBt4oSzpEiXLUSjZDgF8+JHBMIY0KQAA) + format('woff2'); + unicode-range: U+1F00-1FFF; +} +@font-face { + font-family: Roboto; + font-style: italic; + font-weight: 500; + font-display: swap; + src: url(data:font/woff2;base64,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) + format('woff2'); + unicode-range: U+0370-03FF; +} +@font-face { + font-family: Roboto; + font-style: italic; + font-weight: 500; + font-display: swap; + src: url(data:font/woff2;base64,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) + format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, + U+01AF-01B0, U+1EA0-1EF9, U+20AB; +} +@font-face { + font-family: Roboto; + font-style: italic; + font-weight: 500; + font-display: swap; + src: url(data:font/woff2;base64,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) + format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, + U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +@font-face { + font-family: Roboto; + font-style: italic; + font-weight: 500; + font-display: swap; + src: url(data:font/woff2;base64,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) + format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, + U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, + U+FEFF, U+FFFD; +} +@font-face { + font-family: Roboto; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(data:font/woff2;base64,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) + format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, + U+FE2E-FE2F; +} +@font-face { + font-family: Roboto; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(data:font/woff2;base64,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) + format('woff2'); + unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +@font-face { + font-family: Roboto; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(data:font/woff2;base64,d09GMgABAAAAAALsAA4AAAAABWAAAAKbAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGiYbIBw2BmAANBEMCoIYgXsLEAABNgIkAxwEIAWCdAcgG0AEAB6HcYyyEjO2Dy0eKLv4XvfsrGs+wIhEBOHOERRRTI2158fc/aln0WYmSJq8uTRSIgUyIVMqpfa/7uYHCqzWDuHREj0f5UuuL+ZAokTaYgiIs5sF5aUutjO7QhBlgMaYvCAIIqqoCggoq0+HjRlX70MGclDLyR3Z8fb0q/ectzCv30obmLesvO5hBhRhcp7kToaLpaRXpL0htKmb5C3rIgzUIwA1fnqrhHSbqXhA3v+sK1wRtcWuhdyg9E5tGXERkaAhroCGeNqCnJxAm6m1Sb58SICvFhXFWnVAAWQoYRjYADJUQQqIYm0uSZKkfpYv1sv21dm9b7kWbV6i3BQ2Z/sOf/hl+ezXH88LRz75pnLuq4/MO/Zx+eyHc3x9VDn3yfx9n1ILyusq3ps75y90fVZ657PJ2iXgF+odHbvzv7Lrm+uTsPR0WJqYcelN7180rHDDnbeWbrx0QHht49uXjCzffOsd5RsvGvHe4yF5o+Ej97/ZMP62+Z+3Wz/08CtZ/FezhpdvG/nb6PMhC9vNvHFx3Du9X47etewROuONg4L0v2eI+L9X7dt0evq+gNihfvWttiuWK4f8VmxWBM/+WK8b8F6Y9evfLf57r9SjuA2URBAobPm/Smni3y3+n1TqgQEACsl5awAI/5AetjNp65A+/38vDAUXaayPL4CMKHYkEFC0DlfIlbAMegyqlmGU2eSTO58TTHX2xLyWvlczc/wY7eDo5WxlYenKyMvNg9Go5MAatqis2Jty2oytLaPupFxOlsgFObsjM05dBxMHVwcMbeFma4xFh8jZxUr2e62Th09I7Bd96I2RI3gzYzqKcsHjqZzGjsamlojTwdmCy9bKFNm7IBcudRU5BU09BQ5eTm5coMaMAw==) + format('woff2'); + unicode-range: U+1F00-1FFF; +} +@font-face { + font-family: Roboto; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(data:font/woff2;base64,d09GMgABAAAAABMAAA4AAAAAIkQAABKpAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGmQbjEocNgZgAIFkEQwKqTygfguBSAABNgIkA4MMBCAFgnQHIBtLHFWHQtg4AAgt+xD8f52gxWG1uR5EatWEsKGGtrrROAfbhgbsqkcTXk+8cSb2t2LbKz7fybPEC/ukeYa3NyHy/D9ptl4bLoAhSAAYADqGVSx0WQHh8fA07v9/zew9c855UgO/QqKTM9GVxCaWLiSi/R+i08U+4Of29xZE90hzRJVRRI2MqR/4UtI5wcAcNqPDApToUSUYjSpcT+QXXn5a+zaz/t9buUVDpmsnSVyZE7W9V3YRW6gkIqFwHZOEz8yZNyAkBtwZfVEjWAD/BrYL002IehYA///at/ruuWv2EJXQqGQIjZBoM3fW3rxv6/Pmr9n8VURk8MZm0uZNVBEb8CpidRMVQqs0Ks39/d7Xgqlu7zjk2DtDHDX28bUfHg0KCwA3QGEkSBBCijSEPHkIRYoQODgINWoQxx2HOOkUBJ4+hKFzEBe4QyBQwDZgGwRowBZSlGAuvdzKCWRuiw0LAJm7wrz8QeZ+t4ggkIHcd0dYELBBsOACaEAHOg5XQDmgtY9ggGOdJj4KarR21W7Qz/TrvSATe1mvCVRcGIQsiPhIjudoTloJ9TammqzPCWpOKuQ6axSCCp8HA/KFIYINo9VM94B67NppH7YAxm/eIPgij8SuR9/C0+8g3w7F39v8Khj8omzm0JiaZ7l444qvMsAnstouq7pYcvKt26TYqlOZOp/mJ234mjCY7oC4/Q72ir1cq9LY7kUvhugtCr+ZRfcFBtgx2lKDfxZa1hkGB1THTUvPyMzKyc0rKCpWonSZsuUrVqpWq56+kamFtY2tnb2jh5cfistNTLY41vTWc0Tlt1JiorKd6v7UNokwHGZi9R6uH6IMq1ydMgn1rlpfRdJRmagylrRQ9X8wSrX7wf57xx+gdCNMI/I+t4wYHQHKxAGV7JALzIgsitkVtyrpMGVL2oas/Zw1BTOKZpQsK5tVMapqTM200xmXh7ezHie8Lvqe9TvhfxYvsB+ZkbItEy9nU8F+0X5Jt7I9FWtO92/3vM743vO/hxLpkbIrk1DOthIxZQe3B689vg/+D1CBNZl4BWuKtouuAZWi0czWdTk4ZkdOQ2FdrEOKceLJHzd+0wWMrsyKIltHLuRXgyFRKyTrHWXsjlU/FIkacrKon6Kntufn0ETrkHjtUzZx0OTqC6s5ahb0BMBjGGDX48uHpcSXF6uKK0JchdfXpeg0wFjTPqXa6SsWQFiDFb6Luektmdq8Z4N7KWCGjUUnqNY6taI0wwYMwVS4D8YXV8Vobo5NszGGXZSBIBHg1IxjKHIstSPR0KKPlhFHzFwyLuwcF3GBi7rSqWIQgkywQkGgLEkLqWlaJt0CsSUNvS5YEjCWsAQUMwYImNwr842jowi8Y0JM0ECRu8FuAChFDxQ923Z0unuLcwCxjCQA8YcZJC5aBgzsP0q0DIqgBEpsLDHu+aMk8qmWAwvGG0MDtMOyI/ED7w5w6K5Hip6vuNrWFPTiRkxM+Atw56KsgxjkXUCePcgnLgYd7oDlvukRcYy33g9gg0YTz0VG5AUpyNEYAzEa72Oi/hVP1PefFflRGw1BicF4d5pl/fn6M0AiIr/QgnXf9XgDCB4AABE8gAPE94GPX0tAW0dXUMjE1EzY3ELE0krUWsxG3NZOwl5SysHRydnF9cxZ5fMXVM6pqqlrHDt+4uL/Pd3HoagcekDvhbgCTP6+eLs90q6MoH0XWoC+krZxS+EoCYJFlnB3fDNhsjLv3F6rHRznZNCbKlonoDXRTkarIDSk1xxI0hACMNKSaDkhRJiO8/HtVemw6+9IFsLMf/H6jjqkCdNzYE55UXgcEqNlGh71xtqjUT4WUtgMhAUsBp1IQS1Z/FgqgwWjVjmi+W3f/f3MKgU+hVbE2IjswKEiAju0NnCsyMZA2kupofZawvnCLDaexe5ahpUONJt+mt5el9lAKtf24NHBRs6rzUOs99eZy/8b8GgtZY9MltWmGGuqj+p9Fg9n7M5yyy8gvzv8NNEfh0dgdBjGRnFpDJctsFewLwYJITYh7PBN0BrrYwbxY7/h0QnPSolGWtH63Ue/y4Z4EKp+1e/Kt4/e9xUUWRKeRdCiB3lzJEcBdb2ZjENDUI400MCh/mHC5jzQvUVwyqpzwwIoJjIWK31xHDHkUc/VTp2lebQ898VFDAKRlbHESclgpk5H+xb3iviP8hg4P5KLcqj6lG1B1KtVaZGdLcf5Umbu77GiUrmjP5L+yG204DQDTJEXhbzQG07pacEr9XiMQfxkxrYhqKY4rzY11lJf+JFPKTImoiOXyHnnZrg5BR0L3d4MduY6f4S5Ar246Lkw5lRVaT1wuCWp83bSKgdeEHPftgFmimisMyfUZvGLuxp3hlw0i3MTEx03iOW+Ic3EXcoVrwRk8k2qJWNISIsyMjKGMSK7fUxrNZ5lcpxFlebvufLghpowjgyFnLLWmsyDxh/UChbdWgt5G61X1rjeMh5x2yMGsrD48ScfBTnlD6yvOH8rk5YsyosXLxnL7PnxlMo7l4Hy1a9w0eUVuQFmw0navrwA8XHJL1Ot6PaQyD4MlRkRrLHSt/9yWN8BF/hpYvp6lpVr8CjHgFtpvfx47sCIA9uQ6DYk1JjXevTO1RRv0eRL1EHqelsRLT/g5eRbJefedI6L5bbPYyLm1kVzqnMoUbeOqubEM+Rsiuy3UzTtY6a7GqJ2x+yuJZ6rOkak0a2y+3nqY5po5NDaJxkb+kp70Fj05xbbMG8L4hcnpjUqbgqjiZ5bo6PDUH2us5/S/GLntZp13empNkvqa4E9+m6fcRm6h9UEEjanZT+VYOA0rFyaxlzEiIWozs524XDLVyWK9Pl1fl9ah4FaFUOaa7luwJI/mAPtbNDGicZR/xiXDklopOMBv2gyrXdXex9Qr0QP+Z7EOLlnlX/v2716wJK3/vx9/2Zw7lmfQqRY6uv47v/z61fvMWl7dsllN+NoRXRLJa4XXQuISQ/IFgIdFCkaM1tZCVhyftWHsWiwi4cO0hypHbDk9rC5sA6ILo0FAnUNr7eP/Db5zbpWokwtbhUEuMnC3XVr88cFez/J7iFMLc8XHivhuHLyN8amDm7M3b3jrBXu5JGPTxvY5dVPZOvQ3iU/pL+XdwoZ8Xufq89w/+EThnvZeuOtCPoNV9PLt1yoL/6/3os0UoZYUL/B9zSevPLvsRwOjNFRv7lUnC2rzUlLrC3PQnmCeSTHGGA52vLb86HKG+QMEy/globeTcxSvU76nFz+ODv8bhE8x4hTU6IeuaLtoumWzMCpCv1KqRw1aiJ71bdMOCdTffXPXFr2LJvaX+aqmJ8L6XkzpTvxu5Hu+Z3JjMzbM31P781kpN2dhP2fbF26LXxG+Ey+G/gWoHE+jwsIuHqOGOD/SAEXGHBtecGA+xg+Fm55l0f0aReLUfB36cIuJN/PtzMbbwTsFOR9Us0Oe6Kq8jgsC1qH/UcoeMrg+YyB+S6mNaUNYJnQfRxuFwIiPKnNnrQpulJ9pjhRb4jlaIWcZvvt/QdyXuT7UsfJznqArbDiL5ADLVQ+tgR7OmE8S5u2vuGwd0N7NwePjLYynPv9fCvaVC5fl8a/9jwqLk1+KH6c/AaiK+or67Hhup8rP2M1WAqqCsCODTpIjOZ0X54mWzgYaVZlrfyXvWC+YJIzWjVDUYRjUt9qUJCW/aOiKuvH39Ra9JPOJz/RJ5X3C67uhJvddHmJauw8Pvu6o68BTf8M3TaAz3nxon2g+J9F6yCouTOW8zyauM/cwVZ9/Wg7r4qF0EFY5WGTR23ztbPDrbqJAr66DlggpQmUCqI2ktc6vji0/VgJ3a+QzRG8tV056+cVrX4rmJIh+aeKVPO7PFMQ9SyxJlrdz2umkgo6VLwwkm7DSeVJPbDIl64j1L1rXxY4YqVb1OoeItSwZWgYP8ntTHlk39jq1HQvuWAJpMe7OzanHp93K3bFxSkldiaOfN8deRF9aYgC2IaA2KZRgvcN75Rk/4DCTCBoP8vWuZRcWp0QlV4XgCoqcY65FgX0nOz/y7TwPkcmKQu8XT9bgHnsS+pg1ZP0pBNIdRH+qounqU4ApWSUCdMlWxr5eepG7hyNzGfm20202RIYdxlCunYFuWYwLbV6oDf13tRVvtTaYRBWsc5ziwotC7RvLP/7unf4GzmfMqzvKukWa16wenuQ8v1pVqNJlqd/SPI5i5qj7oKFDSxoHSfHXLyfVuNFTTpncMWe76upHa+Jqw1i5P/A4LibI1XdCWekYe3qrXSuJCExV/d6oZDBtRLgvIFnSIku72991A1DFxrtU/2J8RcSXMSt2Sl40JeI199ymJ/esURrjGhvWc/PbRqi1ecUpU8u39xPTU7fX5YalZZdyf2BydhDloC3Gy+vG6yn6g9FxhzmP2TEgM151z3aVuySwHNn9V5JB2yxpoK1tZS2s5Dtih37MuMoXx328qaPNW4RMsvhpDTd/5JumdXeztPWSSVFL5De8tqQ7AoWPaLUoY2qn57PHVMtgmM2o46sJW5F/Z5+lK9eSXBu7WAhLlI+sfhKNfKamhssA6acpIosveN6+n5+EUjJJTWS6kvNQBpj8+aQn+EP6O/P87Z1hRLpKNSqkK3h/+gMTznkPUgp7OwayZlPisz+WA+SYzYtq2PPnwQlJQbfKJt6JobRdU+SdhOyvWwn4n7HXNvNaYXRRNFYwZljS+MbfFAoifo5kQqmz0hCffns7BmxmzMpGVP0yv9MSeTBp5R00DvBIf+qeuJmetWnoYc1I+lpVUOgnV8XXpzkp0gvn2CpQbgWkQe5+eeLUoGrAJ+iNpBQ/+MlZjVSrCtkn5cWdKY6++aRiWLwZ/vXZfVf9+Jprrt43qhJpz969Jx6m3/YL+1qaOJCRsK3wkNxOQzXSONrr3rurtk6zL26j4kGDqDWjX96n7eT+hSzFivQGbnFixZSoefqaxz4y485zrlK+Yx03F4m8TWAkBE+TYBmdyh0iRAQ8vAOrkkdakPq/Qmhi8M0u2kCXcmHPJyjqs37TjtyEbUx0c2jqpyiyZtgmhf+0oHuDvKeutM/9PXrR9NGxC47vexqREJuyZ1PIkz8kzWvKEXVDd1PL1NNOfztk0jNacK+mJ78gm6QMKRZ+KngTnB1NcNLFvXJmkjayKXi27Rkk2VsDGX7JAs1Tc8QHOUvgNszUqrugx72JvUHBw67Drv795tVuNp0GyJKL7IBQo+uN+81tuhD3xu6vHTGL+QOQqJtokVIIXcILpcXgUnK/LFrW4HDX3TT5beTB1r/GaIETDHKldelz0df1E4ihfLpdfNpsN1NNHvpb/gsMZB/CQcw8YB+CgyN8yUADVvYm2FSNC2Ph4qm65UMkci0r3epgES22xM3L/qlEKluhrjZ+UuhtjtNV00kwiINsiMt0iE9MiAjMiEzsiAbY81y6HBVyBmoUWy9dbYTKD2Yr0XWr2h5rlg/oxWlCQI4NnPOWI3yuJbLf9Q58iIHcjPOrLZuXI9sE8MD1GCYo6H/uJorUZ++UzRZd6xl4Ii1s+Ae/gS82P1bbJgTAuPg1C15kJdLdvKYYzkvKm3QHph6tVrbmOBiOAwb8Mfc5Y/6oxlh03uQ1fufCXA5uPge1uPHcvgr0B7wDdpxXofNGVXbg358YQOfgBq8KlgZ3ofT7Nu4Gq/uNy5o62c8f/GsrYyeeB61HdvztNxNt9jXF+2qo245pWWT83VGKGurvyDxznOvPJY2vTevxG69OIj3OKdWuFvQaNClgedPvN5rSot7RCb/lIAA/fgek3NTiS5Wrf/p+JcA+OKvoAzAL83hv5/zn/GV6jIcWEEBNLC4f5MJYHUVFPfXgj5XXY13W2TwtHBbA+NMQilHrc8M9eP5KB3n1cDkz9/6LCNe1GDCVC+1utfTOYo1v+SSOc7HAvE4wytTlXUe+RkelmT2KhmFdt5wZg2jjugI5TN0qGeumPHCU7q7xqOJ9UhzbjgIzSSe2aImUZQz1ZW045HSAjNVbmaJ68W6Moh0bPPKbvJBWGvUcrVK7POi7FHLdZS5PIvFJUlsGtTUNGMx5tfIKPnxvE52XGmPglod6sU1vGujF1f5HGi8dZoFMc1DQ3NrXKMRyDd5I7/kieZBc6L5GLOyvpFHEmqF6iTJ732AALfJxsMJFgKwA3SoE2ggwJI3NCRXwI1AG45gcmk4CgvCxuiwMYaGY8mIGU4Ti1CVVxZOFMPgkNgwPx/fCDF1VbVssJhpsMY8wGt08yAPZaFfgYCgQ7MMV5VXeK7CopLyVK6oYHeGCIKUT2S7cAOlC67C/UgG9QblFo2Tmk7cJ202gUvUXU9OCF4lw2ihDIiQXHhAwktVwWGNoCL8amGvIJ8inPdkZW5obOMoJM5HlSraakb/CJ4AAA==) + format('woff2'); + unicode-range: U+0370-03FF; +} +@font-face { + font-family: Roboto; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(data:font/woff2;base64,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) + format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, + U+01AF-01B0, U+1EA0-1EF9, U+20AB; +} +@font-face { + font-family: Roboto; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(data:font/woff2;base64,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) + format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, + U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +@font-face { + font-family: Roboto; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(data:font/woff2;base64,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) + format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, + U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, + U+FEFF, U+FFFD; +} +@font-face { + font-family: Roboto; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url(data:font/woff2;base64,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) + format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, + U+FE2E-FE2F; +} +@font-face { + font-family: Roboto; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url(data:font/woff2;base64,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) + format('woff2'); + unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +@font-face { + font-family: Roboto; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url(data:font/woff2;base64,d09GMgABAAAAAAMAAA4AAAAABWwAAAKuAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGiYbIBw2BmAANBEMCoIYgXkLEAABNgIkAxwEIAWDAAcgG0oEAB6D426JQgSiDJGrY+EepR5ejwf4/fWd+/C1EBKYZDS7sRFxHTf9uCJn/m9Of4qsOwRQBbqEex0QSbKziM9Pj42dA85/tYTLU84Cj+f+PIAlq3AtV5GCrQWUqr11TNFedSEUjKs7rSju46fX7RWCSHFAeYQcQRBEKIqiAgIKlGZBdO5a3w4akEBWj6orkgSzThrq5iF0WjfiKGe7e/0dAHkwOR8nW+GblHR72hyEGmzEl02NcDPu9oBKt35NVVBcoyEuIJNhau72SE3EHkhapkdqCiZGhBhliQWUJVETSCQCNfr8o/boWoBjI3miLHqQC4ojH22AaUBxFAUpIBJlJeIVGIvLFI6PlFi4hGYVs0brZ4ZZlT0rbz1SLT+50xlW3X269vh2x+CpO/n7bw02ebvIys0wMkpteMHUIq4PGfxCRBdKjxXGaDRIc42rK+a/qgeebsfBvjGMiQ14cnJjW8fSe6fHlr2NIrgbeH2jS+k9X+md9WJP/5IvZ8LRg1cQ3gz+dJMePnr2/6ZSiy3c9rHc87Zj4tqOx0WLe1U0VR2OOEt9kq4gV/r/NBEyVbPvpL70poCoTunu3LVVZ4nW3xWV8gAKP5VqBMD10Pruq+7/52x5c4B8EQjkzs5oyJ/1JzxT0mgEACA3XjUZACFDut7UuAEqPZepikCuTcprJBVAcSJREzIBeaYSC4kSGAs2BJU5IFLcQjt+sxNAqr55kwOx947iBrvVCRYwpBuDQusVLFWyFCmCVcEwCg8JVsPPK1GwEjxesNZJv6dyHtID6dYP8UnUCvPAemHBGiA+jD6CVgilD8+tWyfSPRiYXwVJDNNkydPUzvrRmeBZvFdArqSTDSCJ3ALcvDp0JBHWjTK8pb0Qvx7N35CkXo0yFRq1qZAgVaJkYiA7H3AA) + format('woff2'); + unicode-range: U+1F00-1FFF; +} +@font-face { + font-family: Roboto; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url(data:font/woff2;base64,d09GMgABAAAAABK8AA4AAAAAIgAAABJmAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGmQbi3YcNgZgAIFkEQwKqUCgdAuBSAABNgIkA4MMBCAFgwAHIBv5G7MREWwcAAjqiQT/ZYJtzPyxTqRrsF1IYVrRiFiApETA1++dMFq11kZtOhdxHMTvna14XthLn3dGSDLLg/3yf+feJLvv07tDOZClulqMQCikLU04jMMxKJjN/62Zf2Zn6Q/sAXIBXSvkMaRJCZJ8M3t1ycm+ClNhKzzhQnWV6OBa295MdqJv5linkmiJxg/83P7PZUGHMCpH9J/UqI7hqE/HyFAf5qgQjBlEGRlMe0AB/E+trYhYqhYSodDoJpHmFSLRpl9DxF99b+bPbd/9Mul3vXfutinJdmq2SYcgiepGYMWE4fI/gv9/7tXmntsM+A1QMfsJvRlBau7lFt/Ph5aTlIjyh6Qqqytc/ghL4MaOQM7h8RPOAfrZ2RbDVNs3+l+IXHLYYLCHNa0644xAgqSirxU1gIOBlbiLdAndYX0II8IgTDII0wzCLIOwyCBc4cKu4dlNFXaHP9sWTtyR4MD5NAYg9s17mSKyvOboCQrPyOmJoPAqPSoBFN6HZSaDApjwIj0ZeEAw0AKQ1TnJabIHH6vLIPPQAK6M/SiIkW0IU27qT8eZPitTe9bPj6GSZmEW1pHZLyhh6Y3R1dDHYxFqzxOMK4/vhwnFgAZIozS6RzpKqz0eAxqnF9ScZH1kM+i7/1xvAP04Y7L9rQhtAYwt7Zvs6TSmx2iNmchBkcSIjOt7rG1iUNHKPzN5BupWHYpP4V451W06ZyFJ0F6gTvCrVCv5dke0eIM5HaA9+0OgHG/SdfBq/gtKLPcNkwIYfJxc3Dy8/AKCwqIS0jAECo2XV1ZR19I1MDQyNjGztXcmF5gV75JuhfcjmtBT2C5cJ76diLsGUSvXDGrE3EmBe4hOOWmQJOeK88ShqHxc5Zt63PibyVezb8RcH3g+IKryH9Q/gBANq3AgGhFPSt5J5aQzsDI8hQxQATqGCWM/4r7j/5kHlnfWYduf9hGnsPNPlzCtcFk0kMpDtPAssowqoz9iStiUedm6ZB84lVxKxMIpcjqZQgnM80M0HyWj06J5PlqDcxZobuk0lbmuv83aUzqnCUTrUNHOiAQSgl8gevQrQZF5h4sj4rQ8Dwl5a/xliEVJmXXEy02EKZShAC3IQR/KUNKLpHSRd6mCXOKfAgoIJlJ1/lkkK/4sQS2Vkf4JTy+BmPkmvIM1uB95FcqnWBTlH6kO3trKI3TzAK4GJoJpJobFK0ngtgpmuMsDJ6xuTMKW4eyZpPMHlQKhWxM3cGDAYTZhhckJ27QA/wa60QNCXJgBMppdD10DUqDc99jNkVEE37EeTVjgY/exq9/DeykXkpfTJwS4+z7lAGL3IgDMEWyQuIpCLvfjL0cQhzIoY5bxm4E+YE1Ad4zvyyrVVTrAkIQdiR3REyB08wfsXrl+w8UGzKI0bi/wH+Dl2jVhAOwHJKGopPgIU9F04QlCYEwEPwd/io4QPFR11EZzDAY15mIlNuN63O4gSuvz10dLDMdYzMdq7Izy/Z9kDABEZEYPFEaKEQcE2qy2uCQLuO1aZ9jlORQUlThvXPdt2JLQYQ+nx5GkASlD0h9AITPurayQKQ+evHjz4cuPup1AGrY0EUgUGoN1+DXTbVzID1qEz+Bnbx6A3AJrFxjFYNiCBWg/wQF2BrwOZmbLSOegl+CA4wfcef99OCx1J6eWH5zMwg7GZgyMBXX0URAqJXSEjUaGgQqxQfph2Cy1EGecJxxRB/pCn+5At/p+x1i7bG0JB9REf5MJA9012xqp4QbV2Nwddg4Oht3NLb2NhqIyFYpBaTsqspIhs65IVtRLvStJ1ztgrUod2LYscl0PGPOhnFh6iWR4BA3UCNma0DUCSYrIlTobr5Y52om1M/28oqhCuoLOXhmrO/e8E1QN/HYroSQb27LWzczisvfRSbQcZ5wRFdgkFlgSHhD9ChWhHs5u27MiFWCoWDOVdOGeKhZUqahfoYCyjtit6qNGaGJkWDPsxSFU6gMatNbK2hBXrFOv1ezB1MpY3TkZ+OaomFe/80ecEanr5tO+DHB1z2COtNcnCCzU/AGOjFByeZY/geQ6njv3OVyHyQLM+gyokWSlehRVSTF94DWEyrFXXGuEBorAVGEwhskefTMVImhipSJrBHOP0o67tW0FyLKuxzj0NJPPrSM3sdexZ5EHkwd0JE/6iqOTDRkFpFwRXz7KSx2BRwCbCBSTWcayAiv1XQOwRx4JirxUMiboo6yFoHCBr0tPoLWCrY3NYVFNJN4PhW9M3EPDngAloTrnZWSyfro3Ijk6S26GI5gXBUtpIrgtNYs46LbMr9nhnBMrd9xVJIYCskvWkICQugdLG2iCgeOkJZJW0rKuvZrjO17NOMPXB2uG0Yq0EWCYKlB5WaPzuIfkZV/Jaem+jsQ4UPBopGny7O+n3CQk8qLw6YmeVtL50fGV97LmeXdb0WrGOLL6wRQmqj7mQlyz46YdJFat/gkYf3XZgbcPqdeGCEXyHrvKQx9ZM9WTABtljQX68egqAu+9iazbIEeMIztTXLCkBKPSGgawR9roqGzXnNGE/YSBCytXxYtlV7FGEueLgtmyTMV535FH98G/IcalXkmsunu84y7nwPY3Oe5dgZmnU4C8fDC1BzhTW3Ykytry6a+S9b63/CTC7uMjU/BB00cFtsgkdNb4KpllmW9qHM8nTw473U1BW3ml0fJbzacKAt3iadT4y63LIUzhnPt8RayRUSHjhkTDPM0k0K36YW5sycJGSh5JPQPPSevb3tr+vmy5/rfZPL3vKNEAQ6WhogIBw8xbbEX6wp79YhCFBFUiQSiY0/LQzXJnlomivpDJorJE4I5dDwAKYKj0X8hlWmRCf4xqlmQhNW8D++CHYONV0eyyrLgXb9D4ud+k0vjwxJyQ4p9gkl7tfX5hdRYw1LH1yWZvcCsERkVNxR5gqHvBNcEM6GcAhsoAvcyRM1dau3qy5tTonrZ4qewlVTWQuEwVswwU0w206e35qUiR2MvwKbGbYSKFT+mVwS0V9pQorKzLAShNcnL+A7fn47dbzPlOTYwJnGozhW33W21WcKiRfCdazeAmA707jfw3MgvIe8+v85hj/00e/IRGcQmerxf+O25v57bIpz21Vc2KuoIjpIbafMQAHNAvr7z89/LiegkotQxpccrN7Fx4pGgo+D9BhYuPZnfkIHnPeUwEV9Ihsi+Ca+kQhaIVtlWjEQ0Bs4/rkgPgrNCfv/+ikvKAR5TtLctAzr+XVW2v+DT3d1mOVy3+rFyeG6ldJmfXLMIfHS4P7D/hTMIN4RECAzC3vLXNLUgWFpEWib+PuKY5fSZBxJKQh9T6FsX/RzjCRyc8wXoFxLeQHfUv7gLmPtStEOycyu2dCIed7MyIDnbw+WTKqV3CLtXL5axaH8esmh7w6BOf1Pg0Au712VdFys0+6toCaqTYXrxEMywyXw68jH0kPaDwg0qXfUX1TQXPladCJQtA0Cafv3g+pTL6C1N5RzsOM60H3Wq14D8z2sE/9Jdp9CiM3jlQLrUUolhyS76i/pD8QeWBhJWLqxexFk4/r/zEZCh3rneCmxkwXhbJ/79DBq2L29WYxVVs+zXiNZOO5+utFQCTtP0hFKq++q9JzU+kdhg9ujd6HIXUVP/sH6jbQ2pHUON7/3va03+2B3OmCz04ZWDW3zcw2YE53Y3tpYLuRYtioYZzx7/t/WX6IaT5Q4TEyPoiJKyB+n7A+AE99Rf+L5zIgMebGZI53DBMWu2511jfdXcj8kOBAEli68/a3fjobFxf+HSdOLpv5Cimt0FiKqqdJBsffXPtK5jeJGCZcqx5W4Qn8I5DukNRgxcuPRf/zcn2Qo82Fd3GV/zCrI98ilRrVXHVqq46o4AGCq20rW93xkPCu3w0jqgWLRZvfPuwc5Tsfm0XMKMZuefvpjg0+6dmBYUW5sce8nHrTausTE4iN0ZD7pztTeAkfNj/JyzAs0bfFhZg/wec6PdNN0Zm7FIFncUutenGOfsZ6QYtEJ84PxJE1sS7yT+elrc+55VBHZ3Zr5QW8FeMqcwqHqpcIGeXL0wfaVxNFCJXnoMQrcDYgjBJb9nQI7Ztv0auL+9PNu0akZ39gtMcTY1C7OOunt7ZYWoxzfOODi/yNd/tRs2t3WIeA6Oj1Kb+H16JVnMJnkZ+9sIPiaE45zA3G/Kcm3FeZGC0tXiSVIzYJS27WEOXGik51wcMo0sgSCOwF5PaLkyfusREi6R7JAfFxrZZkXnpBDC/mG70y+7Fkz9maLV3ej8cXj//cRitdlnmpuYmeTUthby6eePzTZXtnO2npBVkBURpBDZjQROV0UU7IW8RPV7glf+XmO2JcxGbJMp6Yb8CarlTNynTRyV5hf/HNVYRAW7/e9L2tkwyg0xTZ8FQ936VrE9OhZfDrHjVldpwifDCChFispyiq0ESYpMz70IojrDFuyjLfmSycJAs0M2apjQNXWpQS1LMrQs7htBedOapgn1LXr+9CdZU4Z2Wv38Pxzx63smlPJCPdH76V5eXe/eJ2IWJOBKK/mCXSQpBqZpntpLyTk3M5tLSo0nnB0C21Jn28eHCy7DEjNC04oUTYiUtXXivEENNdyDaFiw5GBREKig7qSnNmXF90v+4B9uKvdl/HlSCzQsS+1zTv3ryh0fFTc+5VVEcn9llHiNEnWal0dL5nKzChXM9xeNZpPKzYHKJHOt6+ISOYpQ81UU1UQBt6Ol+4TQIyxGqUYNpjW8HmF4niX9Lf4XjQJm8Wdt+BndaIZITdUhc/2AkH53u3t5kY+WwgMQMdq63SBRm9zbltXyoLf/bTJdWYhPdou+2UERGzrcjbbVLmQYmoCdHKGkWO7Yxgn6Wwv/5yHN+NE6PQ3STvo2SYNMG1k/0t8Hih4sB50koE8J+PBe66hsQ0kOx/ueG1AW3+/viy53Dfi4V+Fb7xvAmfu1twKOQ9nrtFt5QXlewK/ZpsWDLuv+HcesGgr4p8QGRyS+qTw5PLCvJ25Y/4JvLh0Zpa0ePL2wtaNuzd3nJJOYNxktaoTqTdM1tQZbOvPNLJYIcEmpNFJW/QFMi4iwVKHwMHrk2KUszVYrs+Xn7mLwI1QSIsigp1O89i1tRXfwc8Ezews/nruLFx/S6U2bCeYCAQvUbnSIcpqK6l9xXHAKj2oDy9u9npD68LcjBfQU4BOyja2O0MtKQpxs/Qu9cvqCb48BcmK54ud+zE+s/cTwf9+vgt/AljqP5xPZUczQyR2wdDCDAQhswFYgALNDxCQOJtBqbNCxlKarIstl4EMAElQB7BibonuMhR6iP+pGOaavOlvphYkEAJHTRw0b0McAQESUq1GiwwRwpTG/p8GEMvXRz/A99DM/vGK5AjqOonERZSEtL0OEPCBm98yJdsR2bsNXVTKPsh6X0fkzL+2gFhh3KyAzjPPjjxYdMtX9Z4cpgDx90/2sDPk6rMRru+IAyX4gbBdIxCxmDiKRZjP7FoqHmSxsLpJYIY7oflN+saKV1cX/p4plTVBTH8BgcwVWtnTIoEdswb118MQUs8SBcOLr5whWNB24CHqiCWeA2KEvvxvQmaZatrO1XXJlgtbkkL0ShzSdHnl+whdHY8qOti7BFzQ9nzYIdUg8yIQlGfHnjdNa8hdCSOM0CxH0L6vXe9OaaCcUsT8MWIo9NV+djsuAXbRDAlD22UUcm5LDRXxbRHQC+f21UB8AvxP3335G9W3uBuwxgDzgABsCauNkB9hKoMfvEs0DgZLVnUSvSIMc+KA98xQFvshylzqJMc8PFDm9WBEtnlqly0SUx6HwAXzzi+RQzeodr1nOJH4SiTFAuaO6fuz471M8gV9BGXuPOZumuZaKVI6AM+bJRYo3pzp21qS/s6wTLCpCQpbzzirbkYq0qeWao0BRzQZ0ryEEZ84TRjCeU/O5Jh5f8hWlgmo1Rxyv1ul5Y2yxrhctCEZ0TSJnbyJJGx+cXyfKNqrObPM03rboaKssNqZTuzxNdqQP5a1YtaEL14GxwbzDyQLpJM+klTVQPqhPVh2oVl1joZ8b1PbUTJL3XgAB4poGQIQyq+iRkAtckwcWOvhAKGJoVwEOALWbQ5biYg4Gy2Wk3i/FiF8b8Ck/kv8EaWHYFLKRIRZYuToxYmaSQcESY79OSwoUlilq+I1kEdVEpINE1JasZqIjKVlHSkUSJpG56ivAImYaUQavSjMySRMkfI0uisAne89NliFOTlQDKpXByutw51q3xNOEjPRUBFvBbV3cpyoeJECuKui2bLoaGL74UVZM1iwyx6rNjwYozj6TiVSTghHCyWzpeJAA=) + format('woff2'); + unicode-range: U+0370-03FF; +} +@font-face { + font-family: Roboto; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url(data:font/woff2;base64,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) + format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, + U+01AF-01B0, U+1EA0-1EF9, U+20AB; +} +@font-face { + font-family: Roboto; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url(data:font/woff2;base64,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) + format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, + U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +@font-face { + font-family: Roboto; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url(data:font/woff2;base64,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) + format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, + U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, + U+FEFF, U+FFFD; +} + +@font-face { + font-family: Fira Code; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(data:font/woff;base64,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) + format('woff'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, + U+FE2E-FE2F; +} +@font-face { + font-family: Fira Code; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(data:font/woff;base64,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) + format('woff'); + unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +@font-face { + font-family: Fira Code; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(data:font/woff;base64,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) + format('woff'); + unicode-range: U+1F00-1FFF; +} +@font-face { + font-family: Fira Code; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(data:font/woff;base64,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) + format('woff'); + unicode-range: U+0370-03FF; +} +@font-face { + font-family: Fira Code; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(data:font/woff;base64,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) + format('woff'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, + U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +@font-face { + font-family: Fira Code; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(data:font/woff;base64,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) + format('woff'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, + U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, + U+FEFF, U+FFFD; +} + +.graphiql-container *{box-sizing:border-box}.graphiql-container,.CodeMirror-info,.CodeMirror-lint-tooltip,reach-portal{--color-primary: 320, 95%, 43%;--color-secondary: 242, 51%, 61%;--color-tertiary: 188, 100%, 36%;--color-info: 208, 100%, 46%;--color-success: 158, 60%, 42%;--color-warning: 36, 100%, 41%;--color-error: 13, 93%, 58%;--color-neutral: 219, 28%, 32%;--color-base: 219, 28%, 100%;--alpha-secondary: .76;--alpha-tertiary: .5;--alpha-background-heavy: .15;--alpha-background-medium: .1;--alpha-background-light: .07;--font-family: "Roboto", sans-serif;--font-family-mono: "Fira Code", monospace;--font-size-hint:.75rem;--font-size-inline-code:.8125rem;--font-size-body:.9375rem;--font-size-h4:1.125rem;--font-size-h3:1.375rem;--font-size-h2:1.8125rem;--font-weight-regular: 400;--font-weight-medium: 500;--line-height: 1.5;--px-2: 2px;--px-4: 4px;--px-6: 6px;--px-8: 8px;--px-10: 10px;--px-12: 12px;--px-16: 16px;--px-20: 20px;--px-24: 24px;--border-radius-2: 2px;--border-radius-4: 4px;--border-radius-8: 8px;--border-radius-12: 12px;--popover-box-shadow: 0px 6px 20px rgba(59, 76, 106, .13), 0px 1.34018px 4.46726px rgba(59, 76, 106, .0774939), 0px .399006px 1.33002px rgba(59, 76, 106, .0525061);--popover-border: none;--sidebar-width: 60px;--toolbar-width: 40px;--session-header-height: 51px}@media (prefers-color-scheme: dark){body:not(.graphiql-light) .graphiql-container,body:not(.graphiql-light) .CodeMirror-info,body:not(.graphiql-light) .CodeMirror-lint-tooltip,body:not(.graphiql-light) reach-portal{--color-primary: 338, 100%, 67%;--color-secondary: 243, 100%, 77%;--color-tertiary: 188, 100%, 44%;--color-info: 208, 100%, 72%;--color-success: 158, 100%, 42%;--color-warning: 30, 100%, 80%;--color-error: 13, 100%, 58%;--color-neutral: 219, 29%, 78%;--color-base: 219, 29%, 18%;--popover-box-shadow: none;--popover-border: 1px solid hsl(var(--color-neutral))}}body.graphiql-dark .graphiql-container,body.graphiql-dark .CodeMirror-info,body.graphiql-dark .CodeMirror-lint-tooltip,body.graphiql-dark reach-portal{--color-primary: 338, 100%, 67%;--color-secondary: 243, 100%, 77%;--color-tertiary: 188, 100%, 44%;--color-info: 208, 100%, 72%;--color-success: 158, 100%, 42%;--color-warning: 30, 100%, 80%;--color-error: 13, 100%, 58%;--color-neutral: 219, 29%, 78%;--color-base: 219, 29%, 18%;--popover-box-shadow: none;--popover-border: 1px solid hsl(var(--color-neutral))}:is(.graphiql-container,.CodeMirror-info,.CodeMirror-lint-tooltip,reach-portal),:is(.graphiql-container,.CodeMirror-info,.CodeMirror-lint-tooltip,reach-portal):is(button){color:hsla(var(--color-neutral),1);font-family:var(--font-family);font-size:var(--font-size-body);font-weight:var(----font-weight-regular);line-height:var(--line-height)}:is(.graphiql-container,.CodeMirror-info,.CodeMirror-lint-tooltip,reach-portal) input{color:hsla(var(--color-neutral),1);font-family:var(--font-family);font-size:var(--font-size-caption)}:is(.graphiql-container,.CodeMirror-info,.CodeMirror-lint-tooltip,reach-portal) input::placeholder{color:hsla(var(--color-neutral),var(--alpha-secondary))}:is(.graphiql-container,.CodeMirror-info,.CodeMirror-lint-tooltip,reach-portal) a{color:hsl(var(--color-primary))}:is(.graphiql-container,.CodeMirror-info,.CodeMirror-lint-tooltip,reach-portal) a:focus{outline:hsl(var(--color-primary)) auto 1px}.graphiql-un-styled,button.graphiql-un-styled{all:unset;border-radius:var(--border-radius-4);cursor:pointer}:is(.graphiql-un-styled,button.graphiql-un-styled):hover{background-color:hsla(var(--color-neutral),var(--alpha-background-light))}:is(.graphiql-un-styled,button.graphiql-un-styled):active{background-color:hsla(var(--color-neutral),var(--alpha-background-medium))}:is(.graphiql-un-styled,button.graphiql-un-styled):focus{outline:hsla(var(--color-neutral),var(--alpha-background-heavy)) auto 1px}.graphiql-button,button.graphiql-button{background-color:hsla(var(--color-neutral),var(--alpha-background-light));border:none;border-radius:var(--border-radius-4);color:hsla(var(--color-neutral),1);cursor:pointer;font-size:var(--font-size-body);padding:var(--px-8) var(--px-12)}:is(.graphiql-button,button.graphiql-button):hover,:is(.graphiql-button,button.graphiql-button):active{background-color:hsla(var(--color-neutral),var(--alpha-background-medium))}:is(.graphiql-button,button.graphiql-button):focus{outline:hsla(var(--color-neutral),var(--alpha-background-heavy)) auto 1px}.graphiql-button-success:is(.graphiql-button,button.graphiql-button){background-color:hsla(var(--color-success),var(--alpha-background-heavy))}.graphiql-button-error:is(.graphiql-button,button.graphiql-button){background-color:hsla(var(--color-error),var(--alpha-background-heavy))}.graphiql-button-group{background-color:hsla(var(--color-neutral),var(--alpha-background-light));border-radius:calc(var(--border-radius-4) + var(--px-4));display:flex;padding:var(--px-4)}.graphiql-button-group>button.graphiql-button{background-color:transparent}.graphiql-button-group>button.graphiql-button:hover{background-color:hsla(var(--color-neutral),var(--alpha-background-light))}.graphiql-button-group>button.graphiql-button.active{background-color:hsl(var(--color-base));cursor:default}.graphiql-button-group>*+*{margin-left:var(--px-8)}:root{--reach-dialog: 1}[data-reach-dialog-overlay]{background:hsla(0,0%,0%,.33);position:fixed;top:0;right:0;bottom:0;left:0;overflow:auto}[data-reach-dialog-content]{width:50vw;margin:10vh auto;background:white;padding:2rem;outline:none}[data-reach-dialog-overlay]{align-items:center;background-color:hsla(var(--color-neutral),var(--alpha-background-heavy));display:flex;justify-content:center;z-index:10}[data-reach-dialog-content]{background-color:hsl(var(--color-base));border:var(--popover-border);border-radius:var(--border-radius-12);box-shadow:var(--popover-box-shadow);margin:0;max-height:80vh;max-width:80vw;overflow:auto;padding:0;width:unset}.graphiql-dialog-close>svg{color:hsla(var(--color-neutral),var(--alpha-secondary));display:block;height:var(--px-12);padding:var(--px-12);width:var(--px-12)}:root{--reach-listbox: 1}[data-reach-listbox-popover]{display:block;position:absolute;min-width:-moz-fit-content;min-width:-webkit-min-content;min-width:min-content;padding:.25rem 0;background:hsl(0,0%,100%);outline:none;border:solid 1px hsla(0,0%,0%,.25)}[data-reach-listbox-popover]:focus-within{box-shadow:0 0 4px Highlight;outline:-webkit-focus-ring-color auto 4px}[data-reach-listbox-popover][hidden]{display:none}[data-reach-listbox-list]{margin:0;padding:0;list-style:none}[data-reach-listbox-list]:focus{box-shadow:none;outline:none}[data-reach-listbox-option]{display:block;margin:0;padding:.25rem .5rem;white-space:nowrap;user-select:none}[data-reach-listbox-option][data-current-nav]{background:hsl(211,81%,46%);color:#fff}[data-reach-listbox-option][data-current-selected]{font-weight:bolder}[data-reach-listbox-option][data-current-selected][data-confirming]{animation:flash .1s;animation-iteration-count:1}[data-reach-listbox-option][aria-disabled=true]{opacity:.5}[data-reach-listbox-button]{display:inline-flex;align-items:center;justify-content:space-between;padding:1px 10px 2px;border:1px solid;border-color:rgb(216,216,216) rgb(209,209,209) rgb(186,186,186);cursor:default;user-select:none}[data-reach-listbox-button][aria-disabled=true]{opacity:.5}[data-reach-listbox-arrow]{margin-left:.5rem;display:block;font-size:.5em}[data-reach-listbox-group-label]{display:block;margin:0;padding:.25rem .5rem;white-space:nowrap;user-select:none;font-weight:bolder}@keyframes flash{0%{background:hsla(211,81%,36%,1);color:#fff;opacity:1}50%{opacity:.5;background:inherit;color:inherit}to{background:hsla(211,81%,36%,1);color:#fff;opacity:1}}:root{--reach-menu-button: 1}[data-reach-menu]{position:relative}[data-reach-menu-popover]{display:block;position:absolute}[data-reach-menu-popover][hidden]{display:none}[data-reach-menu-list],[data-reach-menu-items]{display:block;white-space:nowrap;border:solid 1px hsla(0,0%,0%,.25);background:hsla(0,100%,100%,.99);outline:none;padding:1rem 0;font-size:85%}[data-reach-menu-item]{display:block;user-select:none}[data-reach-menu-item]{cursor:pointer;display:block;color:inherit;font:inherit;text-decoration:initial;padding:5px 20px}[data-reach-menu-item][data-selected]{background:hsl(211,81%,36%);color:#fff;outline:none}[data-reach-menu-item][aria-disabled]{opacity:.5;cursor:not-allowed}[data-reach-listbox-popover],[data-reach-menu-list]{background-color:hsl(var(--color-base));border:var(--popover-border);border-radius:var(--border-radius-8);box-shadow:var(--popover-box-shadow);font-size:inherit;max-width:250px;padding:var(--px-4)}[data-reach-listbox-option],[data-reach-menu-item]{border-radius:var(--border-radius-4);font-size:inherit;margin:var(--px-4);overflow:hidden;padding:var(--px-6) var(--px-8);text-overflow:ellipsis;white-space:nowrap}[data-reach-listbox-option][data-selected],[data-reach-menu-item][data-selected],[data-reach-listbox-option][data-current-nav],[data-reach-menu-item][data-current-nav],[data-reach-listbox-option]:hover,[data-reach-menu-item]:hover{background-color:hsla(var(--color-neutral),var(--alpha-background-light));color:inherit}[data-reach-listbox-option]:not(:first-child),[data-reach-menu-item]:not(:first-child){margin-top:0}[data-reach-listbox-button]{border:none;cursor:pointer;padding:0}:is(.graphiql-markdown-description,.graphiql-markdown-deprecation,.CodeMirror-hint-information-description,.CodeMirror-hint-information-deprecation-reason,.CodeMirror-info .info-description,.CodeMirror-info .info-deprecation) blockquote{margin-left:0;margin-right:0;padding-left:var(--px-8)}:is(.graphiql-markdown-description,.graphiql-markdown-deprecation,.CodeMirror-hint-information-description,.CodeMirror-hint-information-deprecation-reason,.CodeMirror-info .info-description,.CodeMirror-info .info-deprecation) code,:is(.graphiql-markdown-description,.graphiql-markdown-deprecation,.CodeMirror-hint-information-description,.CodeMirror-hint-information-deprecation-reason,.CodeMirror-info .info-description,.CodeMirror-info .info-deprecation) pre{border-radius:var(--border-radius-4);font-family:var(--font-family-mono);font-size:var(--font-size-inline-code)}:is(.graphiql-markdown-description,.graphiql-markdown-deprecation,.CodeMirror-hint-information-description,.CodeMirror-hint-information-deprecation-reason,.CodeMirror-info .info-description,.CodeMirror-info .info-deprecation) code{padding:var(--px-2)}:is(.graphiql-markdown-description,.graphiql-markdown-deprecation,.CodeMirror-hint-information-description,.CodeMirror-hint-information-deprecation-reason,.CodeMirror-info .info-description,.CodeMirror-info .info-deprecation) pre{overflow:auto;padding:var(--px-6) var(--px-8)}:is(.graphiql-markdown-description,.graphiql-markdown-deprecation,.CodeMirror-hint-information-description,.CodeMirror-hint-information-deprecation-reason,.CodeMirror-info .info-description,.CodeMirror-info .info-deprecation) pre code{background-color:initial;border-radius:0;padding:0}:is(.graphiql-markdown-description,.graphiql-markdown-deprecation,.CodeMirror-hint-information-description,.CodeMirror-hint-information-deprecation-reason,.CodeMirror-info .info-description,.CodeMirror-info .info-deprecation) ol,:is(.graphiql-markdown-description,.graphiql-markdown-deprecation,.CodeMirror-hint-information-description,.CodeMirror-hint-information-deprecation-reason,.CodeMirror-info .info-description,.CodeMirror-info .info-deprecation) ul{padding-left:var(--px-16)}:is(.graphiql-markdown-description,.graphiql-markdown-deprecation,.CodeMirror-hint-information-description,.CodeMirror-hint-information-deprecation-reason,.CodeMirror-info .info-description,.CodeMirror-info .info-deprecation) ol{list-style-type:decimal}:is(.graphiql-markdown-description,.graphiql-markdown-deprecation,.CodeMirror-hint-information-description,.CodeMirror-hint-information-deprecation-reason,.CodeMirror-info .info-description,.CodeMirror-info .info-deprecation) ul{list-style-type:disc}:is(.graphiql-markdown-description,.graphiql-markdown-deprecation,.CodeMirror-hint-information-description,.CodeMirror-hint-information-deprecation-reason,.CodeMirror-info .info-description,.CodeMirror-info .info-deprecation) img{border-radius:var(--border-radius-4);max-height:120px;max-width:100%}:is(.graphiql-markdown-description,.graphiql-markdown-deprecation,.CodeMirror-hint-information-description,.CodeMirror-hint-information-deprecation-reason,.CodeMirror-info .info-description,.CodeMirror-info .info-deprecation)>:first-child{margin-top:0}:is(.graphiql-markdown-description,.graphiql-markdown-deprecation,.CodeMirror-hint-information-description,.CodeMirror-hint-information-deprecation-reason,.CodeMirror-info .info-description,.CodeMirror-info .info-deprecation)>:last-child{margin-bottom:0}:is(.graphiql-markdown-description,.CodeMirror-hint-information-description,.CodeMirror-info .info-description) a{color:hsl(var(--color-primary));text-decoration:none}:is(.graphiql-markdown-description,.CodeMirror-hint-information-description,.CodeMirror-info .info-description) a:hover{text-decoration:underline}:is(.graphiql-markdown-description,.CodeMirror-hint-information-description,.CodeMirror-info .info-description) blockquote{border-left:1.5px solid hsla(var(--color-neutral),var(--alpha-tertiary))}:is(.graphiql-markdown-description,.CodeMirror-hint-information-description,.CodeMirror-info .info-description) code,:is(.graphiql-markdown-description,.CodeMirror-hint-information-description,.CodeMirror-info .info-description) pre{background-color:hsla(var(--color-neutral),var(--alpha-background-light));color:hsla(var(--color-neutral),1)}:is(.graphiql-markdown-description,.CodeMirror-hint-information-description,.CodeMirror-info .info-description)>*{margin:var(--px-12) 0}:is(.graphiql-markdown-deprecation,.CodeMirror-hint-information-deprecation-reason,.CodeMirror-info .info-deprecation) a{color:hsl(var(--color-warning));text-decoration:underline}:is(.graphiql-markdown-deprecation,.CodeMirror-hint-information-deprecation-reason,.CodeMirror-info .info-deprecation) blockquote{border-left:1.5px solid hsl(var(--color-warning))}:is(.graphiql-markdown-deprecation,.CodeMirror-hint-information-deprecation-reason,.CodeMirror-info .info-deprecation) code,:is(.graphiql-markdown-deprecation,.CodeMirror-hint-information-deprecation-reason,.CodeMirror-info .info-deprecation) pre{background-color:hsla(var(--color-warning),var(--alpha-background-heavy))}:is(.graphiql-markdown-deprecation,.CodeMirror-hint-information-deprecation-reason,.CodeMirror-info .info-deprecation)>*{margin:var(--px-8) 0}.graphiql-markdown-preview>:not(:first-child){display:none}.CodeMirror-hint-information-deprecation,.CodeMirror-info .info-deprecation{background-color:hsla(var(--color-warning),var(--alpha-background-light));border:1px solid hsl(var(--color-warning));border-radius:var(--border-radius-4);color:hsl(var(--color-warning));margin-top:var(--px-12);padding:var(--px-6) var(--px-8)}.CodeMirror-hint-information-deprecation-label,.CodeMirror-info .info-deprecation-label{font-size:var(--font-size-hint);font-weight:var(--font-weight-medium)}.CodeMirror-hint-information-deprecation-reason,.CodeMirror-info .info-deprecation-reason{margin-top:var(--px-6)}.graphiql-spinner{height:56px;margin:auto;margin-top:var(--px-16);width:56px}.graphiql-spinner:after{animation:rotation .8s linear 0s infinite;border:4px solid transparent;border-radius:100%;border-top:4px solid hsla(var(--color-neutral),var(--alpha-tertiary));content:"";display:inline-block;height:46px;vertical-align:middle;width:46px}@keyframes rotation{0%{transform:rotate(0)}to{transform:rotate(360deg)}}:root{--reach-tooltip: 1}[data-reach-tooltip]{z-index:1;pointer-events:none;position:absolute;padding:.25em .5em;box-shadow:2px 2px 10px #0000001a;white-space:nowrap;font-size:85%;background:#f0f0f0;color:#444;border:solid 1px #ccc}[data-reach-tooltip]{background:hsl(var(--color-base));border:var(--popover-border);border-radius:var(--border-radius-4);box-shadow:var(--popover-box-shadow);color:hsl(var(--color-neutral));font-size:inherit;padding:var(--px-4) var(--px-6)}.graphiql-tabs{display:flex;overflow-x:auto;padding:var(--px-12)}.graphiql-tabs>:not(:first-child){margin-left:var(--px-12)}.graphiql-tab{align-items:stretch;border-radius:var(--border-radius-8);color:hsla(var(--color-neutral),var(--alpha-secondary));display:flex}.graphiql-tab>button.graphiql-tab-close{visibility:hidden}.graphiql-tab.graphiql-tab-active>button.graphiql-tab-close,.graphiql-tab:hover>button.graphiql-tab-close,.graphiql-tab:focus-within>button.graphiql-tab-close{visibility:unset}.graphiql-tab.graphiql-tab-active{background-color:hsla(var(--color-neutral),var(--alpha-background-heavy));color:hsla(var(--color-neutral),1)}button.graphiql-tab-button{padding:var(--px-4) 0 var(--px-4) var(--px-8)}button.graphiql-tab-close{align-items:center;display:flex;padding:var(--px-4) var(--px-8)}button.graphiql-tab-close>svg{height:var(--px-8);width:var(--px-8)}.graphiql-history-header{font-size:var(--font-size-h2);font-weight:var(--font-weight-medium)}.graphiql-history-items{margin:var(--px-16) 0 0;list-style:none;padding:0}.graphiql-history-item{border-radius:var(--border-radius-4);color:hsla(var(--color-neutral),var(--alpha-secondary));display:flex;font-size:var(--font-size-inline-code);font-family:var(--font-family-mono);height:34px}.graphiql-history-item:hover{color:hsla(var(--color-neutral),1);background-color:hsla(var(--color-neutral),var(--alpha-background-light))}.graphiql-history-item:not(:first-child){margin-top:var(--px-4)}.graphiql-history-item.editable{background-color:hsla(var(--color-primary),var(--alpha-background-medium))}.graphiql-history-item.editable>input{background:transparent;border:none;flex:1;margin:0;outline:none;padding:0 var(--px-10);width:100%}.graphiql-history-item.editable>input::placeholder{color:hsla(var(--color-neutral),var(--alpha-secondary))}.graphiql-history-item.editable>button{color:hsl(var(--color-primary));padding:0 var(--px-10)}.graphiql-history-item.editable>button:active{background-color:hsla(var(--color-primary),var(--alpha-background-heavy))}.graphiql-history-item.editable>button:focus{outline:hsl(var(--color-primary)) auto 1px}.graphiql-history-item.editable>button>svg{display:block}button.graphiql-history-item-label{flex:1;padding:var(--px-8) var(--px-10);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}button.graphiql-history-item-action{align-items:center;color:hsla(var(--color-neutral),var(--alpha-secondary));display:flex;padding:var(--px-8) var(--px-6)}button.graphiql-history-item-action:hover{color:hsla(var(--color-neutral),1)}button.graphiql-history-item-action>svg{height:14px;width:14px}.graphiql-history-item-spacer{height:var(--px-16)}.graphiql-doc-explorer-default-value{color:hsl(var(--color-success))}a.graphiql-doc-explorer-type-name{color:hsl(var(--color-warning));text-decoration:none}a.graphiql-doc-explorer-type-name:hover{text-decoration:underline}a.graphiql-doc-explorer-type-name:focus{outline:hsl(var(--color-warning)) auto 1px}.graphiql-doc-explorer-argument>*+*{margin-top:var(--px-12)}.graphiql-doc-explorer-argument-name{color:hsl(var(--color-secondary))}.graphiql-doc-explorer-argument-deprecation{background-color:hsla(var(--color-warning),var(--alpha-background-light));border:1px solid hsl(var(--color-warning));border-radius:var(--border-radius-4);color:hsl(var(--color-warning));padding:var(--px-8)}.graphiql-doc-explorer-argument-deprecation-label{font-size:var(--font-size-hint);font-weight:var(--font-weight-medium)}.graphiql-doc-explorer-deprecation{background-color:hsla(var(--color-warning),var(--alpha-background-light));border:1px solid hsl(var(--color-warning));border-radius:var(--px-4);color:hsl(var(--color-warning));padding:var(--px-8)}.graphiql-doc-explorer-deprecation-label{font-size:var(--font-size-hint);font-weight:var(--font-weight-medium)}.graphiql-doc-explorer-directive{color:hsl(var(--color-secondary))}.graphiql-doc-explorer-section-title{align-items:center;display:flex;font-size:var(--font-size-hint);font-weight:var(--font-weight-medium);line-height:1}.graphiql-doc-explorer-section-title>svg{height:var(--px-16);margin-right:var(--px-8);width:var(--px-16)}.graphiql-doc-explorer-section-content{margin-left:var(--px-8);margin-top:var(--px-16)}.graphiql-doc-explorer-section-content>*+*{margin-top:var(--px-16)}.graphiql-doc-explorer-root-type{color:hsl(var(--color-info))}:root{--reach-combobox: 1}[data-reach-combobox-popover]{border:solid 1px hsla(0,0%,0%,.25);background:hsla(0,100%,100%,.99);font-size:85%}[data-reach-combobox-list]{list-style:none;margin:0;padding:0;user-select:none}[data-reach-combobox-option]{cursor:pointer;margin:0;padding:.25rem .5rem}[data-reach-combobox-option][aria-selected=true]{background:hsl(211,10%,95%)}[data-reach-combobox-option]:hover{background:hsl(211,10%,92%)}[data-reach-combobox-option][aria-selected=true]:hover{background:hsl(211,10%,90%)}[data-suggested-value]{font-weight:700}[data-reach-combobox]{color:hsla(var(--color-neutral),var(--alpha-secondary))}[data-reach-combobox]:not([data-state="idle"]){border:var(--popover-border);border-radius:var(--border-radius-4);box-shadow:var(--popover-box-shadow);color:hsla(var(--color-neutral),1)}[data-reach-combobox]:not([data-state="idle"]) .graphiql-doc-explorer-search-input{background:hsl(var(--color-base));border-bottom-left-radius:0;border-bottom-right-radius:0}.graphiql-doc-explorer-search-input{align-items:center;background-color:hsla(var(--color-neutral),var(--alpha-background-light));border-radius:var(--border-radius-4);display:flex;padding:var(--px-8) var(--px-12)}[data-reach-combobox-input]{border:none;background-color:transparent;margin-left:var(--px-4);width:100%}[data-reach-combobox-input]:focus{outline:none}[data-reach-combobox-popover]{background-color:hsl(var(--color-base));border:none;border-bottom-left-radius:var(--border-radius-4);border-bottom-right-radius:var(--border-radius-4);border-top:1px solid hsla(var(--color-neutral),var(--alpha-background-heavy));max-height:400px;overflow-y:auto;position:relative}[data-reach-combobox-list]{font-size:var(--font-size-body);padding:var(--px-4)}[data-reach-combobox-option]{border-radius:var(--border-radius-4);color:hsla(var(--color-neutral),var(--alpha-secondary));overflow-x:hidden;padding:var(--px-8) var(--px-12);text-overflow:ellipsis;white-space:nowrap}[data-reach-combobox-option][data-highlighted]{background-color:hsla(var(--color-neutral),var(--alpha-background-light))}[data-reach-combobox-option]:hover{background-color:hsla(var(--color-neutral),var(--alpha-background-medium))}[data-reach-combobox-option][data-highlighted]:hover{background-color:hsla(var(--color-neutral),var(--alpha-background-heavy))}[data-reach-combobox-option]+[data-reach-combobox-option]{margin-top:var(--px-4)}.graphiql-doc-explorer-search-type{color:hsl(var(--color-info))}.graphiql-doc-explorer-search-field{color:hsl(var(--color-warning))}.graphiql-doc-explorer-search-argument{color:hsl(var(--color-secondary))}.graphiql-doc-explorer-search-divider{color:hsla(var(--color-neutral),var(--alpha-secondary));font-size:var(--font-size-hint);font-weight:var(--font-weight-medium);margin-top:var(--px-8);padding:var(--px-8) var(--px-12)}.graphiql-doc-explorer-search-empty{color:hsla(var(--color-neutral),var(--alpha-secondary));padding:var(--px-8) var(--px-12)}a.graphiql-doc-explorer-field-name{color:hsl(var(--color-info));text-decoration:none}a.graphiql-doc-explorer-field-name:hover{text-decoration:underline}a.graphiql-doc-explorer-field-name:focus{outline:hsl(var(--color-info)) auto 1px}.graphiql-doc-explorer-item>:not(:first-child){margin-top:var(--px-12)}.graphiql-doc-explorer-argument-multiple{margin-left:var(--px-8)}.graphiql-doc-explorer-enum-value{color:hsl(var(--color-info))}.graphiql-doc-explorer-header{display:flex;justify-content:space-between;position:relative}.graphiql-doc-explorer-header:focus-within .graphiql-doc-explorer-title{visibility:hidden}.graphiql-doc-explorer-header:focus-within .graphiql-doc-explorer-back:not(:focus){color:transparent}.graphiql-doc-explorer-header-content{display:flex;flex-direction:column;min-width:0}.graphiql-doc-explorer-search{height:100%;position:absolute;right:0;top:0}.graphiql-doc-explorer-search:focus-within{left:0}.graphiql-doc-explorer-search [data-reach-combobox-input]{height:24px;width:4ch}.graphiql-doc-explorer-search [data-reach-combobox-input]:focus{width:100%}a.graphiql-doc-explorer-back{align-items:center;color:hsla(var(--color-neutral),var(--alpha-secondary));display:flex;text-decoration:none}a.graphiql-doc-explorer-back:hover{text-decoration:underline}a.graphiql-doc-explorer-back:focus{outline:hsla(var(--color-neutral),var(--alpha-secondary)) auto 1px}a.graphiql-doc-explorer-back:focus+.graphiql-doc-explorer-title{visibility:unset}a.graphiql-doc-explorer-back>svg{height:var(--px-8);margin-right:var(--px-8);width:var(--px-8)}.graphiql-doc-explorer-title{font-weight:var(--font-weight-medium);font-size:var(--font-size-h2);overflow-x:hidden;text-overflow:ellipsis;white-space:nowrap}.graphiql-doc-explorer-title:not(:first-child){font-size:var(--font-size-h3);margin-top:var(--px-8)}.graphiql-doc-explorer-content>*{color:hsla(var(--color-neutral),var(--alpha-secondary));margin-top:var(--px-20)}.graphiql-doc-explorer-error{background-color:hsla(var(--color-error),var(--alpha-background-heavy));border:1px solid hsl(var(--color-error));border-radius:var(--border-radius-8);color:hsl(var(--color-error));padding:var(--px-8) var(--px-12)}.CodeMirror{font-family:monospace;height:300px;color:#000;direction:ltr}.CodeMirror-lines{padding:4px 0}.CodeMirror pre.CodeMirror-line,.CodeMirror pre.CodeMirror-line-like{padding:0 4px}.CodeMirror-scrollbar-filler,.CodeMirror-gutter-filler{background-color:#fff}.CodeMirror-gutters{border-right:1px solid #ddd;background-color:#f7f7f7;white-space:nowrap}.CodeMirror-linenumber{padding:0 3px 0 5px;min-width:20px;text-align:right;color:#999;white-space:nowrap}.CodeMirror-guttermarker{color:#000}.CodeMirror-guttermarker-subtle{color:#999}.CodeMirror-cursor{border-left:1px solid black;border-right:none;width:0}.CodeMirror div.CodeMirror-secondarycursor{border-left:1px solid silver}.cm-fat-cursor .CodeMirror-cursor{width:auto;border:0!important;background:#7e7}.cm-fat-cursor div.CodeMirror-cursors{z-index:1}.cm-fat-cursor .CodeMirror-line::selection,.cm-fat-cursor .CodeMirror-line>span::selection,.cm-fat-cursor .CodeMirror-line>span>span::selection{background:transparent}.cm-fat-cursor .CodeMirror-line::-moz-selection,.cm-fat-cursor .CodeMirror-line>span::-moz-selection,.cm-fat-cursor .CodeMirror-line>span>span::-moz-selection{background:transparent}.cm-fat-cursor{caret-color:transparent}@-moz-keyframes blink{50%{background-color:transparent}}@-webkit-keyframes blink{50%{background-color:transparent}}@keyframes blink{50%{background-color:transparent}}.cm-tab{display:inline-block;text-decoration:inherit}.CodeMirror-rulers{position:absolute;left:0;right:0;top:-50px;bottom:0;overflow:hidden}.CodeMirror-ruler{border-left:1px solid #ccc;top:0;bottom:0;position:absolute}.cm-s-default .cm-header{color:#00f}.cm-s-default .cm-quote{color:#090}.cm-negative{color:#d44}.cm-positive{color:#292}.cm-header,.cm-strong{font-weight:700}.cm-em{font-style:italic}.cm-link{text-decoration:underline}.cm-strikethrough{text-decoration:line-through}.cm-s-default .cm-keyword{color:#708}.cm-s-default .cm-atom{color:#219}.cm-s-default .cm-number{color:#164}.cm-s-default .cm-def{color:#00f}.cm-s-default .cm-variable-2{color:#05a}.cm-s-default .cm-variable-3,.cm-s-default .cm-type{color:#085}.cm-s-default .cm-comment{color:#a50}.cm-s-default .cm-string{color:#a11}.cm-s-default .cm-string-2{color:#f50}.cm-s-default .cm-meta,.cm-s-default .cm-qualifier{color:#555}.cm-s-default .cm-builtin{color:#30a}.cm-s-default .cm-bracket{color:#997}.cm-s-default .cm-tag{color:#170}.cm-s-default .cm-attribute{color:#00c}.cm-s-default .cm-hr{color:#999}.cm-s-default .cm-link{color:#00c}.cm-s-default .cm-error,.cm-invalidchar{color:red}.CodeMirror-composing{border-bottom:2px solid}div.CodeMirror span.CodeMirror-matchingbracket{color:#0b0}div.CodeMirror span.CodeMirror-nonmatchingbracket{color:#a22}.CodeMirror-matchingtag{background:rgba(255,150,0,.3)}.CodeMirror-activeline-background{background:#e8f2ff}.CodeMirror{position:relative;overflow:hidden;background:white}.CodeMirror-scroll{overflow:scroll!important;margin-bottom:-50px;margin-right:-50px;padding-bottom:50px;height:100%;outline:none;position:relative;z-index:0}.CodeMirror-sizer{position:relative;border-right:50px solid transparent}.CodeMirror-vscrollbar,.CodeMirror-hscrollbar,.CodeMirror-scrollbar-filler,.CodeMirror-gutter-filler{position:absolute;z-index:6;display:none;outline:none}.CodeMirror-vscrollbar{right:0;top:0;overflow-x:hidden;overflow-y:scroll}.CodeMirror-hscrollbar{bottom:0;left:0;overflow-y:hidden;overflow-x:scroll}.CodeMirror-scrollbar-filler{right:0;bottom:0}.CodeMirror-gutter-filler{left:0;bottom:0}.CodeMirror-gutters{position:absolute;left:0;top:0;min-height:100%;z-index:3}.CodeMirror-gutter{white-space:normal;height:100%;display:inline-block;vertical-align:top;margin-bottom:-50px}.CodeMirror-gutter-wrapper{position:absolute;z-index:4;background:none!important;border:none!important}.CodeMirror-gutter-background{position:absolute;top:0;bottom:0;z-index:4}.CodeMirror-gutter-elt{position:absolute;cursor:default;z-index:4}.CodeMirror-gutter-wrapper ::selection{background-color:transparent}.CodeMirror-gutter-wrapper ::-moz-selection{background-color:transparent}.CodeMirror-lines{cursor:text;min-height:1px}.CodeMirror pre.CodeMirror-line,.CodeMirror pre.CodeMirror-line-like{-moz-border-radius:0;-webkit-border-radius:0;border-radius:0;border-width:0;background:transparent;font-family:inherit;font-size:inherit;margin:0;white-space:pre;word-wrap:normal;line-height:inherit;color:inherit;z-index:2;position:relative;overflow:visible;-webkit-tap-highlight-color:transparent;-webkit-font-variant-ligatures:contextual;font-variant-ligatures:contextual}.CodeMirror-wrap pre.CodeMirror-line,.CodeMirror-wrap pre.CodeMirror-line-like{word-wrap:break-word;white-space:pre-wrap;word-break:normal}.CodeMirror-linebackground{position:absolute;left:0;right:0;top:0;bottom:0;z-index:0}.CodeMirror-linewidget{position:relative;z-index:2;padding:.1px}.CodeMirror-rtl pre{direction:rtl}.CodeMirror-code{outline:none}.CodeMirror-scroll,.CodeMirror-sizer,.CodeMirror-gutter,.CodeMirror-gutters,.CodeMirror-linenumber{-moz-box-sizing:content-box;box-sizing:content-box}.CodeMirror-measure{position:absolute;width:100%;height:0;overflow:hidden;visibility:hidden}.CodeMirror-cursor{position:absolute;pointer-events:none}.CodeMirror-measure pre{position:static}div.CodeMirror-cursors{visibility:hidden;position:relative;z-index:3}div.CodeMirror-dragcursors,.CodeMirror-focused div.CodeMirror-cursors{visibility:visible}.CodeMirror-selected{background:#d9d9d9}.CodeMirror-focused .CodeMirror-selected{background:#d7d4f0}.CodeMirror-crosshair{cursor:crosshair}.CodeMirror-line::selection,.CodeMirror-line>span::selection,.CodeMirror-line>span>span::selection{background:#d7d4f0}.CodeMirror-line::-moz-selection,.CodeMirror-line>span::-moz-selection,.CodeMirror-line>span>span::-moz-selection{background:#d7d4f0}.cm-searching{background-color:#ffa;background-color:#ff06}.cm-force-border{padding-right:.1px}@media print{.CodeMirror div.CodeMirror-cursors{visibility:hidden}}.cm-tab-wrap-hack:after{content:""}span.CodeMirror-selectedtext{background:none}.CodeMirror{height:100%;position:absolute;width:100%}.CodeMirror{font-family:var(--font-family-mono)}.CodeMirror,.CodeMirror-gutters{background:none;background-color:var(--editor-background, hsl(var(--color-base)))}.CodeMirror-linenumber{padding:0}.CodeMirror-gutters{border:none}.cm-s-graphiql{color:hsla(var(--color-neutral),var(--alpha-tertiary))}.cm-s-graphiql .cm-keyword{color:hsl(var(--color-primary))}.cm-s-graphiql .cm-def{color:hsl(var(--color-tertiary))}.cm-s-graphiql .cm-punctuation{color:hsla(var(--color-neutral),var(--alpha-tertiary))}.cm-s-graphiql .cm-variable{color:hsl(var(--color-secondary))}.cm-s-graphiql .cm-atom{color:hsl(var(--color-tertiary))}.cm-s-graphiql .cm-number{color:hsl(var(--color-success))}.cm-s-graphiql .cm-string{color:hsl(var(--color-warning))}.cm-s-graphiql .cm-builtin{color:hsl(var(--color-success))}.cm-s-graphiql .cm-string-2{color:hsl(var(--color-secondary))}.cm-s-graphiql .cm-attribute,.cm-s-graphiql .cm-meta{color:hsl(var(--color-tertiary))}.cm-s-graphiql .cm-property{color:hsl(var(--color-info))}.cm-s-graphiql .cm-qualifier{color:hsl(var(--color-secondary))}.cm-s-graphiql .cm-comment{color:hsla(var(--color-neutral),var(--alpha-secondary))}.cm-s-graphiql .cm-ws{color:hsla(var(--color-neutral),var(--alpha-tertiary))}.cm-s-graphiql .cm-invalidchar{color:hsl(var(--color-error))}.cm-s-graphiql .CodeMirror-cursor{border-left:2px solid hsla(var(--color-neutral),var(--alpha-secondary))}.cm-s-graphiql .CodeMirror-linenumber{color:hsla(var(--color-neutral),var(--alpha-tertiary))}div.CodeMirror span.CodeMirror-matchingbracket,div.CodeMirror span.CodeMirror-nonmatchingbracket{color:hsl(var(--color-warning))}.CodeMirror-selected,.CodeMirror-focused .CodeMirror-selected{background:hsla(var(--color-neutral),var(--alpha-background-heavy))}.CodeMirror-dialog{background:inherit;color:inherit;left:0;right:0;overflow:hidden;padding:var(--px-2) var(--px-6);position:absolute;z-index:6}.CodeMirror-dialog-top{border-bottom:1px solid hsla(var(--color-neutral),var(--alpha-background-heavy));padding-bottom:var(--px-12);top:0}.CodeMirror-dialog-bottom{border-top:1px solid hsla(var(--color-neutral),var(--alpha-background-heavy));bottom:0;padding-top:var(--px-12)}.CodeMirror-search-hint{display:none}.CodeMirror-dialog input{border:1px solid hsla(var(--color-neutral),var(--alpha-background-heavy));border-radius:var(--border-radius-4);padding:var(--px-4)}.CodeMirror-dialog input:focus{outline:hsl(var(--color-primary)) solid 2px}.cm-searching{background-color:hsla(var(--color-warning),var(--alpha-background-light));padding-bottom:1.5px;padding-top:.5px}.CodeMirror-foldmarker{color:#00f;text-shadow:#b9f 1px 1px 2px,#b9f -1px -1px 2px,#b9f 1px -1px 2px,#b9f -1px 1px 2px;font-family:arial;line-height:.3;cursor:pointer}.CodeMirror-foldgutter{width:.7em}.CodeMirror-foldgutter-open,.CodeMirror-foldgutter-folded{cursor:pointer}.CodeMirror-foldgutter-open:after{content:"\25be"}.CodeMirror-foldgutter-folded:after{content:"\25b8"}.CodeMirror-foldgutter{width:var(--px-12)}.CodeMirror-foldmarker{background-color:hsl(var(--color-info));border-radius:var(--border-radius-4);color:hsl(var(--color-base));font-family:inherit;margin:0 var(--px-4);padding:0 var(--px-8);text-shadow:none}.CodeMirror-foldgutter-open,.CodeMirror-foldgutter-folded{color:hsla(var(--color-neutral),var(--alpha-tertiary))}.CodeMirror-foldgutter-open:after,.CodeMirror-foldgutter-folded:after{margin:0 var(--px-2)}.graphiql-editor{height:100%;position:relative;width:100%}.graphiql-editor.hidden{left:-9999px;position:absolute;top:-9999px;visibility:hidden}.CodeMirror-lint-markers{width:16px}.CodeMirror-lint-tooltip{background-color:#ffd;border:1px solid black;border-radius:4px;color:#000;font-family:monospace;font-size:10pt;overflow:hidden;padding:2px 5px;position:fixed;white-space:pre;white-space:pre-wrap;z-index:100;max-width:600px;opacity:0;transition:opacity .4s;-moz-transition:opacity .4s;-webkit-transition:opacity .4s;-o-transition:opacity .4s;-ms-transition:opacity .4s}.CodeMirror-lint-mark{background-position:left bottom;background-repeat:repeat-x}.CodeMirror-lint-mark-warning{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJFhQXEbhTg7YAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAMklEQVQI12NkgIIvJ3QXMjAwdDN+OaEbysDA4MPAwNDNwMCwiOHLCd1zX07o6kBVGQEAKBANtobskNMAAAAASUVORK5CYII=)}.CodeMirror-lint-mark-error{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJDw4cOCW1/KIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg==)}.CodeMirror-lint-marker{background-position:center center;background-repeat:no-repeat;cursor:pointer;display:inline-block;height:16px;width:16px;vertical-align:middle;position:relative}.CodeMirror-lint-message{padding-left:18px;background-position:top left;background-repeat:no-repeat}.CodeMirror-lint-marker-warning,.CodeMirror-lint-message-warning{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAANlBMVEX/uwDvrwD/uwD/uwD/uwD/uwD/uwD/uwD/uwD6twD/uwAAAADurwD2tQD7uAD+ugAAAAD/uwDhmeTRAAAADHRSTlMJ8mN1EYcbmiixgACm7WbuAAAAVklEQVR42n3PUQqAIBBFUU1LLc3u/jdbOJoW1P08DA9Gba8+YWJ6gNJoNYIBzAA2chBth5kLmG9YUoG0NHAUwFXwO9LuBQL1giCQb8gC9Oro2vp5rncCIY8L8uEx5ZkAAAAASUVORK5CYII=)}.CodeMirror-lint-marker-error,.CodeMirror-lint-message-error{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAHlBMVEW7AAC7AACxAAC7AAC7AAAAAAC4AAC5AAD///+7AAAUdclpAAAABnRSTlMXnORSiwCK0ZKSAAAATUlEQVR42mWPOQ7AQAgDuQLx/z8csYRmPRIFIwRGnosRrpamvkKi0FTIiMASR3hhKW+hAN6/tIWhu9PDWiTGNEkTtIOucA5Oyr9ckPgAWm0GPBog6v4AAAAASUVORK5CYII=)}.CodeMirror-lint-marker-multiple{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAMAAADzjKfhAAAACVBMVEUAAAAAAAC/v7914kyHAAAAAXRSTlMAQObYZgAAACNJREFUeNo1ioEJAAAIwmz/H90iFFSGJgFMe3gaLZ0od+9/AQZ0ADosbYraAAAAAElFTkSuQmCC);background-repeat:no-repeat;background-position:right bottom;width:100%;height:100%}.CodeMirror-lint-line-error{background-color:#b74c5114}.CodeMirror-lint-line-warning{background-color:#ffd3001a}.CodeMirror-lint-mark-error,.CodeMirror-lint-mark-warning{background-repeat:repeat-x;background-size:10px 3px;background-position:0 95%}.cm-s-graphiql .CodeMirror-lint-mark-error{color:hsl(var(--color-error))}.CodeMirror-lint-mark-error{background-image:linear-gradient(45deg,transparent 65%,hsl(var(--color-error)) 80%,transparent 90%),linear-gradient(135deg,transparent 5%,hsl(var(--color-error)) 15%,transparent 25%),linear-gradient(135deg,transparent 45%,hsl(var(--color-error)) 55%,transparent 65%),linear-gradient(45deg,transparent 25%,hsl(var(--color-error)) 35%,transparent 50%)}.cm-s-graphiql .CodeMirror-lint-mark-warning{color:hsl(var(--color-warning))}.CodeMirror-lint-mark-warning{background-image:linear-gradient(45deg,transparent 65%,hsl(var(--color-warning)) 80%,transparent 90%),linear-gradient(135deg,transparent 5%,hsl(var(--color-warning)) 15%,transparent 25%),linear-gradient(135deg,transparent 45%,hsl(var(--color-warning)) 55%,transparent 65%),linear-gradient(45deg,transparent 25%,hsl(var(--color-warning)) 35%,transparent 50%)}.CodeMirror-lint-tooltip{background-color:hsl(var(--color-base));border:var(--popover-border);border-radius:var(--border-radius-8);box-shadow:var(--popover-box-shadow);font-size:var(--font-size-body);font-family:var(--font-family);max-width:600px;overflow:hidden;padding:var(--px-12)}.CodeMirror-lint-message-error,.CodeMirror-lint-message-warning{background-image:none;padding:0}.CodeMirror-lint-message-error{color:hsl(var(--color-error))}.CodeMirror-lint-message-warning{color:hsl(var(--color-warning))}.CodeMirror-hints{position:absolute;z-index:10;overflow:hidden;list-style:none;margin:0;padding:2px;-webkit-box-shadow:2px 3px 5px rgba(0,0,0,.2);-moz-box-shadow:2px 3px 5px rgba(0,0,0,.2);box-shadow:2px 3px 5px #0003;border-radius:3px;border:1px solid silver;background:white;font-size:90%;font-family:monospace;max-height:20em;overflow-y:auto}.CodeMirror-hint{margin:0;padding:0 4px;border-radius:2px;white-space:pre;color:#000;cursor:pointer}li.CodeMirror-hint-active{background:#08f;color:#fff}.CodeMirror-hints{background:hsl(var(--color-base));border:var(--popover-border);border-radius:var(--border-radius-8);box-shadow:var(--popover-box-shadow);display:grid;font-family:var(--font-family);font-size:var(--font-size-body);grid-template-columns:auto fit-content(300px);max-height:264px;padding:0}.CodeMirror-hint{border-radius:var(--border-radius-4);color:hsla(var(--color-neutral),var(--alpha-secondary));grid-column:1 / 2;margin:var(--px-4);padding:var(--px-6) var(--px-8)!important}.CodeMirror-hint:not(:first-child){margin-top:0}li.CodeMirror-hint-active{background:hsla(var(--color-primary),var(--alpha-background-medium));color:hsl(var(--color-primary))}.CodeMirror-hint-information{border-left:1px solid hsla(var(--color-neutral),var(--alpha-background-heavy));grid-column:2 / 3;grid-row:1 / 99999;max-height:264px;overflow:auto;padding:var(--px-12)}.CodeMirror-hint-information-header{display:flex;align-items:baseline}.CodeMirror-hint-information-field-name{font-size:var(--font-size-h4);font-weight:var(--font-weight-medium)}.CodeMirror-hint-information-type-name-pill{border:1px solid hsla(var(--color-neutral),var(--alpha-tertiary));border-radius:var(--border-radius-4);color:hsla(var(--color-neutral),var(--alpha-secondary));margin-left:var(--px-6);padding:var(--px-4)}.CodeMirror-hint-information-type-name{color:inherit;text-decoration:none}.CodeMirror-hint-information-type-name:hover{text-decoration:underline dotted}.CodeMirror-hint-information-description{color:hsla(var(--color-neutral),var(--alpha-secondary));margin-top:var(--px-12)}.CodeMirror-info{background-color:hsl(var(--color-base));border:var(--popover-border);border-radius:var(--border-radius-8);box-shadow:var(--popover-box-shadow);color:hsla(var(--color-neutral),1);max-height:300px;max-width:400px;opacity:0;overflow:auto;padding:var(--px-12);position:fixed;transition:opacity .15s;z-index:10}.CodeMirror-info a{color:inherit;text-decoration:none}.CodeMirror-info a:hover{text-decoration:underline dotted}.CodeMirror-info .CodeMirror-info-header{display:flex;align-items:baseline}.CodeMirror-info .CodeMirror-info-header>.type-name,.CodeMirror-info .CodeMirror-info-header>.field-name,.CodeMirror-info .CodeMirror-info-header>.arg-name,.CodeMirror-info .CodeMirror-info-header>.directive-name,.CodeMirror-info .CodeMirror-info-header>.enum-value{font-size:var(--font-size-h4);font-weight:var(--font-weight-medium)}.CodeMirror-info .type-name-pill{border:1px solid hsla(var(--color-neutral),var(--alpha-tertiary));border-radius:var(--border-radius-4);color:hsla(var(--color-neutral),var(--alpha-secondary));margin-left:var(--px-6);padding:var(--px-4)}.CodeMirror-info .info-description{color:hsla(var(--color-neutral),var(--alpha-secondary));margin-top:var(--px-12);overflow:hidden}.CodeMirror-jump-token{text-decoration:underline dotted;cursor:pointer}.auto-inserted-leaf.cm-property{animation-duration:6s;animation-name:insertionFade;border-radius:var(--border-radius-4);padding:var(--px-2)}@keyframes insertionFade{0%,to{background-color:none}15%,85%{background-color:hsla(var(--color-warning),var(--alpha-background-light))}}button.graphiql-toolbar-button{display:flex;align-items:center;justify-content:center;height:var(--toolbar-width);width:var(--toolbar-width)}button.graphiql-toolbar-button.error{background:hsla(var(--color-error),var(--alpha-background-heavy))}.graphiql-execute-button-wrapper{position:relative}button.graphiql-execute-button{background-color:hsl(var(--color-primary));border:none;border-radius:var(--border-radius-8);cursor:pointer;height:var(--toolbar-width);padding:0;width:var(--toolbar-width)}button.graphiql-execute-button:hover{background-color:hsla(var(--color-primary),.9)}button.graphiql-execute-button:active{background-color:hsla(var(--color-primary),.8)}button.graphiql-execute-button:focus{outline:hsla(var(--color-primary),.8) auto 1px}button.graphiql-execute-button>svg{color:#fff;display:block;height:var(--px-16);margin:auto;width:var(--px-16)}.graphiql-toolbar-listbox,button.graphiql-toolbar-menu{display:block;height:var(--toolbar-width);width:var(--toolbar-width)} + +.graphiql-container{background-color:hsl(var(--color-base));display:flex;height:100%;margin:0;overflow:hidden;width:100%}.graphiql-container .graphiql-sidebar{display:flex;flex-direction:column;justify-content:space-between;padding:var(--px-8);width:var(--sidebar-width)}.graphiql-container .graphiql-sidebar .graphiql-sidebar-section{display:flex;flex-direction:column;gap:var(--px-8)}.graphiql-container .graphiql-sidebar button{align-items:center;color:hsla(var(--color-neutral),var(--alpha-secondary));display:flex;height:calc(var(--sidebar-width) - var(--px-8)*2);justify-content:center;width:calc(var(--sidebar-width) - var(--px-8)*2)}.graphiql-container .graphiql-sidebar button.active{color:hsla(var(--color-neutral),1)}.graphiql-container .graphiql-sidebar button:not(:first-child){margin-top:var(--px-4)}.graphiql-container .graphiql-sidebar button>svg{height:var(--px-20);width:var(--px-20)}.graphiql-container .graphiql-main{display:flex;flex:1;min-width:0}.graphiql-container .graphiql-sessions{background-color:hsla(var(--color-neutral),var(--alpha-background-light));border-radius:calc(var(--border-radius-12) + var(--px-8));display:flex;flex:1;flex-direction:column;margin:var(--px-16);margin-left:0;max-height:100%;min-width:0}.graphiql-container .graphiql-session-header{align-items:center;display:flex;height:var(--session-header-height);justify-content:space-between}button.graphiql-tab-add{height:100%;padding:0 var(--px-4)}button.graphiql-tab-add>svg{color:hsla(var(--color-neutral),var(--alpha-secondary));display:block;height:var(--px-16);width:var(--px-16)}.graphiql-add-tab-wrapper{padding:var(--px-12) 0}.graphiql-container .graphiql-session-header-right{align-items:stretch;display:flex}.graphiql-container .graphiql-logo{color:hsla(var(--color-neutral),var(--alpha-secondary));font-size:var(--font-size-h4);font-weight:var(--font-weight-medium);padding:var(--px-12) var(--px-16)}.graphiql-container .graphiql-logo .graphiql-logo-link{color:hsla(var(--color-neutral),var(--alpha-secondary));text-decoration:none}.graphiql-container .graphiql-session{display:flex;flex:1;padding:0 var(--px-8) var(--px-8)}.graphiql-container .graphiql-editors{background-color:hsl(var(--color-base));border-radius:calc(var(--border-radius-12));box-shadow:var(--popover-box-shadow);display:flex;flex:1;flex-direction:column}.graphiql-container .graphiql-editors.full-height{margin-top:calc(var(--px-8) - var(--session-header-height))}.graphiql-container .graphiql-query-editor{border-bottom:1px solid hsla(var(--color-neutral),var(--alpha-background-heavy));display:flex;flex:1;padding:var(--px-16)}.graphiql-container .graphiql-query-editor-wrapper{display:flex;flex:1}.graphiql-container .graphiql-toolbar{margin-left:var(--px-16);width:var(--toolbar-width)}.graphiql-container .graphiql-toolbar>*+*{margin-top:var(--px-8)}.graphiql-toolbar-icon{color:hsla(var(--color-neutral),var(--alpha-tertiary));display:block;height:calc(var(--toolbar-width) - var(--px-8)*2);width:calc(var(--toolbar-width) - var(--px-8)*2)}.graphiql-container .graphiql-editor-tools{align-items:center;cursor:row-resize;display:flex;justify-content:space-between;padding:var(--px-8)}.graphiql-container .graphiql-editor-tools button{color:hsla(var(--color-neutral),var(--alpha-secondary))}.graphiql-container .graphiql-editor-tools button.active{color:hsla(var(--color-neutral),1)}.graphiql-container .graphiql-editor-tools-tabs{cursor:auto;display:flex}.graphiql-container .graphiql-editor-tools-tabs>button{padding:var(--px-8) var(--px-12)}.graphiql-container .graphiql-editor-tools-tabs>button+button{margin-left:var(--px-8)}.graphiql-container .graphiql-editor-tool{flex:1;padding:var(--px-16)}.graphiql-container .graphiql-editor-tool,.graphiql-container .graphiql-editor-tools,.graphiql-container .graphiql-toolbar{position:relative}.graphiql-container .graphiql-response{--editor-background:transparent;display:flex;flex:1;flex-direction:column;position:relative}.graphiql-container .graphiql-response .result-window{flex:1;position:relative}.graphiql-container .graphiql-footer{border-top:1px solid hsla(var(--color-neutral),var(--alpha-background-heavy))}.graphiql-container .graphiql-plugin{border-left:1px solid hsla(var(--color-neutral),var(--alpha-background-heavy));flex:1;overflow-y:auto;padding:var(--px-16)}.graphiql-container .graphiql-horizontal-drag-bar{cursor:col-resize;width:var(--px-12)}.graphiql-container .graphiql-horizontal-drag-bar:hover:after{border:var(--px-2) solid hsla(var(--color-neutral),var(--alpha-background-heavy));border-radius:var(--border-radius-2);content:"";display:block;height:25%;margin:0 auto;position:relative;top:37.5%;width:0}.graphiql-container .graphiql-chevron-icon{color:hsla(var(--color-neutral),var(--alpha-tertiary));display:block;height:var(--px-12);margin:var(--px-12);width:var(--px-12)}.graphiql-spin{animation:spin .8s linear 0s infinite}@keyframes spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}reach-portal .graphiql-dialog-header{align-items:center;display:flex;justify-content:space-between;padding:var(--px-24)}reach-portal .graphiql-dialog-title{font-size:var(--font-size-h3);font-weight:var(--font-weight-medium)}reach-portal .graphiql-dialog-section{align-items:center;border-top:1px solid hsla(var(--color-neutral),var(--alpha-background-heavy));display:flex;justify-content:space-between;padding:var(--px-24)}reach-portal .graphiql-dialog-section>:not(:first-child){margin-left:var(--px-24)}reach-portal .graphiql-dialog-section-title{font-size:var(--font-size-h4);font-weight:var(--font-weight-medium)}reach-portal .graphiql-dialog-section-caption{color:hsla(var(--color-neutral),var(--alpha-secondary))}reach-portal .graphiql-warning-text{color:hsl(var(--color-warning));font-weight:var(--font-weight-medium)}reach-portal .graphiql-table{border-collapse:collapse;width:100%}reach-portal .graphiql-table :is(th,td){border:1px solid hsla(var(--color-neutral),var(--alpha-background-heavy));padding:var(--px-8) var(--px-12)}reach-portal .graphiql-key{background-color:hsla(var(--color-neutral),var(--alpha-background-medium));border-radius:var(--border-radius-4);padding:var(--px-4)}.graphiql-container svg{pointer-events:none} + +/*# sourceMappingURL=graphiql.min.css.map*/ \ No newline at end of file diff --git a/graphql/internal/graphiql/graphiql.min.js b/graphql/internal/graphiql/graphiql.min.js new file mode 100644 index 0000000000..73c32f32a4 --- /dev/null +++ b/graphql/internal/graphiql/graphiql.min.js @@ -0,0 +1,3 @@ +/*! For license information please see graphiql.min.js.LICENSE.txt */ +!function(){var e,t,n={8042:function(e,t){var n,r;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,n=function(){"use strict";function e(){const e={};return e.promise=new Promise(((t,n)=>{e.resolve=t,e.reject=n})),e}Object.defineProperty(t,"__esModule",{value:!0});const n=Symbol(),r=Symbol();function i(){let t=!0;const i=[];let o=e();const a=e(),s=async function*(){for(;;)if(i.length>0)yield i.shift();else{const e=await Promise.race([o.promise,a.promise]);if(e===n)break;if(e!==r)throw e}}();const l=s.return.bind(s);s.return=function(){return t=!1,a.resolve(n),l(...arguments)};const u=s.throw.bind(s);return s.throw=e=>(t=!1,a.resolve(e),u(e)),{pushValue:function(n){!1!==t&&(i.push(n),o.resolve(r),o=e())},asyncIterableIterator:s}}t.applyAsyncIterableIteratorToSink=function(e,t){return(async()=>{try{for await(const n of e)t.next(n);t.complete()}catch(e){t.error(e)}})(),()=>{var t;null===(t=e.return)||void 0===t||t.call(e)}},t.isAsyncIterable=function(e){return"object"==typeof e&&null!==e&&("AsyncGenerator"===e[Symbol.toStringTag]||Symbol.asyncIterator&&Symbol.asyncIterator in e)},t.makeAsyncIterableIteratorFromSink=e=>{const{pushValue:t,asyncIterableIterator:n}=i(),r=e({next:e=>{t(e)},complete:()=>{n.return()},error:e=>{n.throw(e)}}),o=n.return;let a;return n.return=()=>(void 0===a&&(r(),a=o()),a),n},t.makePushPullAsyncIterableIterator=i},void 0===(r=n.apply(t,[]))||(e.exports=r)},7674:function(e,t,n){var r,i;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,void 0===(i="function"==typeof(r=function(){"use strict";var e=Object.create?function(e,t,n,r){void 0===r&&(r=n),Object.defineProperty(e,r,{enumerable:!0,get:function(){return t[n]}})}:function(e,t,n,r){void 0===r&&(r=n),e[r]=t[n]},r=function(t,n){for(var r in t)"default"===r||Object.prototype.hasOwnProperty.call(n,r)||e(n,t,r)};Object.defineProperty(t,"__esModule",{value:!0}),r(n(5313),t),r(n(6718),t),r(n(863),t)})?r.apply(t,[]):r)||(e.exports=i)},5609:function(e,t){var n,r;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,void 0===(r="function"==typeof(n=function(e){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.R=e.P=void 0;var t=Object.defineProperty,n=(e,n)=>t(e,"name",{value:n,configurable:!0});class r{constructor(e,t){this.containsPosition=e=>this.start.line===e.line?this.start.character<=e.character:this.end.line===e.line?this.end.character>=e.character:this.start.line<=e.line&&this.end.line>=e.line,this.start=e,this.end=t}setStart(e,t){this.start=new i(e,t)}setEnd(e,t){this.end=new i(e,t)}}e.R=r,n(r,"Range");class i{constructor(e,t){this.lessThanOrEqualTo=e=>this.linei(e,"name",{value:t,configurable:!0});function a(e,n){const i={schema:e,type:null,parentType:null,inputType:null,directiveDef:null,fieldDef:null,argDef:null,argDefs:null,objectFieldDefs:null};return(0,r.f)(n,(n=>{var r,o;switch(n.kind){case"Query":case"ShortQuery":i.type=e.getQueryType();break;case"Mutation":i.type=e.getMutationType();break;case"Subscription":i.type=e.getSubscriptionType();break;case"InlineFragment":case"FragmentDefinition":n.type&&(i.type=e.getType(n.type));break;case"Field":case"AliasedField":i.fieldDef=i.type&&n.name?s(e,i.parentType,n.name):null,i.type=null===(r=i.fieldDef)||void 0===r?void 0:r.type;break;case"SelectionSet":i.parentType=i.type?(0,t.getNamedType)(i.type):null;break;case"Directive":i.directiveDef=n.name?e.getDirective(n.name):null;break;case"Arguments":const a=n.prevState?"Field"===n.prevState.kind?i.fieldDef:"Directive"===n.prevState.kind?i.directiveDef:"AliasedField"===n.prevState.kind?n.prevState.name&&s(e,i.parentType,n.prevState.name):null:null;i.argDefs=a?a.args:null;break;case"Argument":if(i.argDef=null,i.argDefs)for(let e=0;ee.value===n.name)):null;break;case"ListValue":const c=i.inputType?(0,t.getNullableType)(i.inputType):null;i.inputType=c instanceof t.GraphQLList?c.ofType:null;break;case"ObjectValue":const d=i.inputType?(0,t.getNamedType)(i.inputType):null;i.objectFieldDefs=d instanceof t.GraphQLInputObjectType?d.getFields():null;break;case"ObjectField":const f=n.name&&i.objectFieldDefs?i.objectFieldDefs[n.name]:null;i.inputType=null==f?void 0:f.type;break;case"NamedType":i.type=n.name?e.getType(n.name):null}})),i}function s(e,r,i){return i===n.S.name&&e.getQueryType()===r?n.S:i===n.T.name&&e.getQueryType()===r?n.T:i===n.a.name&&(0,t.isCompositeType)(r)?n.a:r&&r.getFields?r.getFields()[i]:void 0}function l(e,t){for(let n=0;nn(e,"name",{value:t,configurable:!0});function i(e,t){return t.forEach((function(t){t&&"string"!=typeof t&&!Array.isArray(t)&&Object.keys(t).forEach((function(n){if("default"!==n&&!(n in e)){var r=Object.getOwnPropertyDescriptor(t,n);Object.defineProperty(e,n,r.get?r:{enumerable:!0,get:function(){return t[n]}})}}))})),Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}r(i,"_mergeNamespaces");var o={exports:{}};!function(e){function t(t){return function(n,i){var o=i.line,a=n.getLine(o);function s(t){for(var r,s=i.ch,l=0;;){var u=s<=0?-1:a.lastIndexOf(t[0],s-1);if(-1!=u){if(1==l&&ut.lastLine())return null;var r=t.getTokenAt(e.Pos(n,1));if(/\S/.test(r.string)||(r=t.getTokenAt(e.Pos(n,r.end+1))),"keyword"!=r.type||"import"!=r.string)return null;for(var i=n,o=Math.min(t.lastLine(),n+10);i<=o;++i){var a=t.getLine(i).indexOf(";");if(-1!=a)return{startCh:r.end,end:e.Pos(i,a)}}}r(i,"hasImport");var o,a=n.line,s=i(a);if(!s||i(a-1)||(o=i(a-2))&&o.end.line==a-1)return null;for(var l=s.end;;){var u=i(l.line+1);if(null==u)break;l=u.end}return{from:t.clipPos(e.Pos(a,s.startCh+1)),to:l}})),e.registerHelper("fold","include",(function(t,n){function i(n){if(nt.lastLine())return null;var r=t.getTokenAt(e.Pos(n,1));return/\S/.test(r.string)||(r=t.getTokenAt(e.Pos(n,r.end+1))),"meta"==r.type&&"#include"==r.string.slice(0,8)?r.start+8:void 0}r(i,"hasInclude");var o=n.line,a=i(o);if(null==a||null!=i(o-1))return null;for(var s=o;null!=i(s+1);)++s;return{from:e.Pos(o,a+1),to:t.clipPos(e.Pos(s))}}))}(t.a.exports);var a=i({__proto__:null,default:o.exports},[o.exports]);e.b=a})?r.apply(t,i):r)||(e.exports=o)},5728:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[t,n(535)],void 0===(o="function"==typeof(r=function(e,t){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.c=void 0;var n=Object.defineProperty,r=(e,t)=>n(e,"name",{value:t,configurable:!0});function i(e,t){return t.forEach((function(t){t&&"string"!=typeof t&&!Array.isArray(t)&&Object.keys(t).forEach((function(n){if("default"!==n&&!(n in e)){var r=Object.getOwnPropertyDescriptor(t,n);Object.defineProperty(e,n,r.get?r:{enumerable:!0,get:function(){return t[n]}})}}))})),Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}r(i,"_mergeNamespaces");var o={exports:{}};!function(e){var t={pairs:"()[]{}''\"\"",closeBefore:")]}'\":;>",triples:"",explode:"[]{}"},n=e.Pos;function i(e,n){return"pairs"==n&&"string"==typeof e?e:"object"==typeof e&&null!=e[n]?e[n]:t[n]}e.defineOption("autoCloseBrackets",!1,(function(t,n,r){r&&r!=e.Init&&(t.removeKeyMap(o),t.state.closeBrackets=null),n&&(a(i(n,"pairs")),t.state.closeBrackets=n,t.addKeyMap(o))})),r(i,"getOption");var o={Backspace:u,Enter:c};function a(e){for(var t=0;t=0;s--){var c=a[s].head;t.replaceRange("",n(c.line,c.ch-1),n(c.line,c.ch+1),"+delete")}}function c(t){var n=l(t),r=n&&i(n,"explode");if(!r||t.getOption("disableInput"))return e.Pass;for(var o=t.listSelections(),a=0;a0?{line:a.head.line,ch:a.head.ch+t}:{line:a.head.line-1};n.push({anchor:s,head:s})}e.setSelections(n,i)}function f(t){var r=e.cmpPos(t.anchor,t.head)>0;return{anchor:new n(t.anchor.line,t.anchor.ch+(r?-1:1)),head:new n(t.head.line,t.head.ch+(r?1:-1))}}function p(t,r){var o=l(t);if(!o||t.getOption("disableInput"))return e.Pass;var a=i(o,"pairs"),s=a.indexOf(r);if(-1==s)return e.Pass;for(var u,c=i(o,"closeBefore"),p=i(o,"triples"),h=a.charAt(s+1)==r,g=t.listSelections(),v=s%2==0,y=0;y1&&p.indexOf(r)>=0&&t.getRange(n(T.line,T.ch-2),T)==r+r){if(T.ch>2&&/\bstring/.test(t.getTokenTypeAt(n(T.line,T.ch-2))))return e.Pass;b="addFour"}else if(h){var C=0==T.ch?" ":t.getRange(n(T.line,T.ch-1),T);if(e.isWordChar(w)||C==r||e.isWordChar(C))return e.Pass;b="both"}else{if(!v||!(0===w.length||/\s/.test(w)||c.indexOf(w)>-1))return e.Pass;b="both"}else b=h&&m(t,T)?"both":p.indexOf(r)>=0&&t.getRange(T,n(T.line,T.ch+3))==r+r+r?"skipThree":"skip";if(u){if(u!=b)return e.Pass}else u=b}var S=s%2?a.charAt(s-1):r,x=s%2?r:a.charAt(s+1);t.operation((function(){if("skip"==u)d(t,1);else if("skipThree"==u)d(t,3);else if("surround"==u){for(var e=t.getSelections(),n=0;nn(e,"name",{value:t,configurable:!0});function i(e,t){return t.forEach((function(t){t&&"string"!=typeof t&&!Array.isArray(t)&&Object.keys(t).forEach((function(n){if("default"!==n&&!(n in e)){var r=Object.getOwnPropertyDescriptor(t,n);Object.defineProperty(e,n,r.get?r:{enumerable:!0,get:function(){return t[n]}})}}))})),Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}r(i,"_mergeNamespaces");var o={exports:{}};e.a=o,function(e,n){t.c,e.exports=function(){var e=navigator.userAgent,t=navigator.platform,n=/gecko\/\d/i.test(e),i=/MSIE \d/.test(e),o=/Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(e),a=/Edge\/(\d+)/.exec(e),s=i||o||a,l=s&&(i?document.documentMode||6:+(a||o)[1]),u=!a&&/WebKit\//.test(e),c=u&&/Qt\/\d+\.\d+/.test(e),d=!a&&/Chrome\//.test(e),f=/Opera\//.test(e),p=/Apple Computer/.test(navigator.vendor),h=/Mac OS X 1\d\D([8-9]|\d\d)\D/.test(e),m=/PhantomJS/.test(e),g=p&&(/Mobile\/\w+/.test(e)||navigator.maxTouchPoints>2),v=/Android/.test(e),y=g||v||/webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(e),b=g||/Mac/.test(t),E=/\bCrOS\b/.test(e),T=/win/i.test(t),w=f&&e.match(/Version\/(\d*\.\d*)/);w&&(w=Number(w[1])),w&&w>=15&&(f=!1,u=!0);var C=b&&(c||f&&(null==w||w<12.11)),S=n||s&&l>=9;function x(e){return new RegExp("(^|\\s)"+e+"(?:$|\\s)\\s*")}r(x,"classTest");var k,N=r((function(e,t){var n=e.className,r=x(t).exec(n);if(r){var i=n.slice(r.index+r[0].length);e.className=n.slice(0,r.index)+(i?r[1]+i:"")}}),"rmClass");function _(e){for(var t=e.childNodes.length;t>0;--t)e.removeChild(e.firstChild);return e}function O(e,t){return _(e).appendChild(t)}function I(e,t,n,r){var i=document.createElement(e);if(n&&(i.className=n),r&&(i.style.cssText=r),"string"==typeof t)i.appendChild(document.createTextNode(t));else if(t)for(var o=0;o=t)return a+(t-o);a+=s-o,a+=n-a%n,o=s+1}}g?F=r((function(e){e.selectionStart=0,e.selectionEnd=e.value.length}),"selectInput"):s&&(F=r((function(e){try{e.select()}catch(e){}}),"selectInput")),r(P,"bind"),r(j,"copyObj"),r(V,"countColumn");var U=r((function(){this.id=null,this.f=null,this.time=0,this.handler=P(this.onTimeout,this)}),"Delayed");function B(e,t){for(var n=0;n=t)return r+Math.min(a,t-i);if(i+=o-r,r=o+1,(i+=n-i%n)>=t)return r}}r(W,"findColumn");var K=[""];function Q(e){for(;K.length<=e;)K.push(X(K)+" ");return K[e]}function X(e){return e[e.length-1]}function Y(e,t){for(var n=[],r=0;r"€"&&(e.toUpperCase()!=e.toLowerCase()||te.test(e))}function re(e,t){return t?!!(t.source.indexOf("\\w")>-1&&ne(e))||t.test(e):ne(e)}function ie(e){for(var t in e)if(e.hasOwnProperty(t)&&e[t])return!1;return!0}r(ne,"isWordCharBasic"),r(re,"isWordChar"),r(ie,"isEmpty");var oe=/[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/;function ae(e){return e.charCodeAt(0)>=768&&oe.test(e)}function se(e,t,n){for(;(n<0?t>0:tn?-1:1;;){if(t==n)return t;var i=(t+n)/2,o=r<0?Math.ceil(i):Math.floor(i);if(o==t)return e(o)?t:n;e(o)?n=o:t=o+r}}function ue(e,t,n,r){if(!e)return r(t,n,"ltr",0);for(var i=!1,o=0;ot||t==n&&a.to==t)&&(r(Math.max(a.from,t),Math.min(a.to,n),1==a.level?"rtl":"ltr",o),i=!0)}i||r(t,n,"ltr")}r(ae,"isExtendingChar"),r(se,"skipExtendingChars"),r(le,"findFirst"),r(ue,"iterateBidiSections");var ce=null;function de(e,t,n){var r;ce=null;for(var i=0;it)return i;o.to==t&&(o.from!=o.to&&"before"==n?r=i:ce=i),o.from==t&&(o.from!=o.to&&"before"!=n?r=i:ce=i)}return null!=r?r:ce}r(de,"getBidiPartAt");var fe=function(){var e="bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN",t="nnnnnnNNr%%r,rNNmmmmmmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmmmnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmnNmmmmmmrrmmNmmmmrr1111111111";function n(n){return n<=247?e.charAt(n):1424<=n&&n<=1524?"R":1536<=n&&n<=1785?t.charAt(n-1536):1774<=n&&n<=2220?"r":8192<=n&&n<=8203?"w":8204==n?"b":"L"}r(n,"charType");var i=/[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/,o=/[stwN]/,a=/[LRr]/,s=/[Lb1n]/,l=/[1n]/;function u(e,t,n){this.level=e,this.from=t,this.to=n}return r(u,"BidiSpan"),function(e,t){var r="ltr"==t?"L":"R";if(0==e.length||"ltr"==t&&!i.test(e))return!1;for(var c=e.length,d=[],f=0;f-1&&(r[t]=i.slice(0,o).concat(i.slice(o+1)))}}}function ye(e,t){var n=ge(e,t);if(n.length)for(var r=Array.prototype.slice.call(arguments,2),i=0;i0}function we(e){e.prototype.on=function(e,t){me(this,e,t)},e.prototype.off=function(e,t){ve(this,e,t)}}function Ce(e){e.preventDefault?e.preventDefault():e.returnValue=!1}function Se(e){e.stopPropagation?e.stopPropagation():e.cancelBubble=!0}function xe(e){return null!=e.defaultPrevented?e.defaultPrevented:0==e.returnValue}function ke(e){Ce(e),Se(e)}function Ne(e){return e.target||e.srcElement}function _e(e){var t=e.which;return null==t&&(1&e.button?t=1:2&e.button?t=3:4&e.button&&(t=2)),b&&e.ctrlKey&&1==t&&(t=3),t}r(ge,"getHandlers"),r(ve,"off"),r(ye,"signal"),r(be,"signalDOMEvent"),r(Ee,"signalCursorActivity"),r(Te,"hasHandler"),r(we,"eventMixin"),r(Ce,"e_preventDefault"),r(Se,"e_stopPropagation"),r(xe,"e_defaultPrevented"),r(ke,"e_stop"),r(Ne,"e_target"),r(_e,"e_button");var Oe,Ie,De=function(){if(s&&l<9)return!1;var e=I("div");return"draggable"in e||"dragDrop"in e}();function Le(e){if(null==Oe){var t=I("span","​");O(e,I("span",[t,document.createTextNode("x")])),0!=e.firstChild.offsetHeight&&(Oe=t.offsetWidth<=1&&t.offsetHeight>2&&!(s&&l<8))}var n=Oe?I("span","​"):I("span"," ",null,"display: inline-block; width: 1px; margin-right: -1px");return n.setAttribute("cm-text",""),n}function Ae(e){if(null!=Ie)return Ie;var t=O(e,document.createTextNode("AخA")),n=k(t,0,1).getBoundingClientRect(),r=k(t,1,2).getBoundingClientRect();return _(e),!(!n||n.left==n.right)&&(Ie=r.right-n.right<3)}r(Le,"zeroWidthElement"),r(Ae,"hasBadBidiRects");var Me,Re=3!="\n\nb".split(/\n/).length?function(e){for(var t=0,n=[],r=e.length;t<=r;){var i=e.indexOf("\n",t);-1==i&&(i=e.length);var o=e.slice(t,"\r"==e.charAt(i-1)?i-1:i),a=o.indexOf("\r");-1!=a?(n.push(o.slice(0,a)),t+=a+1):(n.push(o),t=i+1)}return n}:function(e){return e.split(/\r\n?|\n/)},Fe=window.getSelection?function(e){try{return e.selectionStart!=e.selectionEnd}catch(e){return!1}}:function(e){var t;try{t=e.ownerDocument.selection.createRange()}catch(e){}return!(!t||t.parentElement()!=e)&&0!=t.compareEndPoints("StartToEnd",t)},Pe="oncopy"in(Me=I("div"))||(Me.setAttribute("oncopy","return;"),"function"==typeof Me.oncopy),je=null;function Ve(e){if(null!=je)return je;var t=O(e,I("span","x")),n=t.getBoundingClientRect(),r=k(t,0,1).getBoundingClientRect();return je=Math.abs(n.left-r.left)>1}r(Ve,"hasBadZoomedRects");var Ue={},Be={};function $e(e,t){arguments.length>2&&(t.dependencies=Array.prototype.slice.call(arguments,2)),Ue[e]=t}function qe(e,t){Be[e]=t}function He(e){if("string"==typeof e&&Be.hasOwnProperty(e))e=Be[e];else if(e&&"string"==typeof e.name&&Be.hasOwnProperty(e.name)){var t=Be[e.name];"string"==typeof t&&(t={name:t}),(e=ee(t,e)).name=t.name}else{if("string"==typeof e&&/^[\w\-]+\/[\w\-]+\+xml$/.test(e))return He("application/xml");if("string"==typeof e&&/^[\w\-]+\/[\w\-]+\+json$/.test(e))return He("application/json")}return"string"==typeof e?{name:e}:e||{name:"null"}}function Ge(e,t){t=He(t);var n=Ue[t.name];if(!n)return Ge(e,"text/plain");var r=n(e,t);if(ze.hasOwnProperty(t.name)){var i=ze[t.name];for(var o in i)i.hasOwnProperty(o)&&(r.hasOwnProperty(o)&&(r["_"+o]=r[o]),r[o]=i[o])}if(r.name=t.name,t.helperType&&(r.helperType=t.helperType),t.modeProps)for(var a in t.modeProps)r[a]=t.modeProps[a];return r}r($e,"defineMode"),r(qe,"defineMIME"),r(He,"resolveMode"),r(Ge,"getMode");var ze={};function We(e,t){j(t,ze.hasOwnProperty(e)?ze[e]:ze[e]={})}function Ke(e,t){if(!0===t)return t;if(e.copyState)return e.copyState(t);var n={};for(var r in t){var i=t[r];i instanceof Array&&(i=i.concat([])),n[r]=i}return n}function Qe(e,t){for(var n;e.innerMode&&(n=e.innerMode(t))&&n.mode!=e;)t=n.state,e=n.mode;return n||{mode:e,state:t}}function Xe(e,t,n){return!e.startState||e.startState(t,n)}r(We,"extendMode"),r(Ke,"copyState"),r(Qe,"innerMode"),r(Xe,"startState");var Ye=r((function(e,t,n){this.pos=this.start=0,this.string=e,this.tabSize=t||8,this.lastColumnPos=this.lastColumnValue=0,this.lineStart=0,this.lineOracle=n}),"StringStream");function Je(e,t){if((t-=e.first)<0||t>=e.size)throw new Error("There is no line "+(t+e.first)+" in the document.");for(var n=e;!n.lines;)for(var r=0;;++r){var i=n.children[r],o=i.chunkSize();if(t=e.first&&tn?at(n,Je(e,n).text.length):ht(t,Je(e,t.line).text.length)}function ht(e,t){var n=e.ch;return null==n||n>t?at(e.line,t):n<0?at(e.line,0):e}function mt(e,t){for(var n=[],r=0;r=this.string.length},Ye.prototype.sol=function(){return this.pos==this.lineStart},Ye.prototype.peek=function(){return this.string.charAt(this.pos)||void 0},Ye.prototype.next=function(){if(this.post},Ye.prototype.eatSpace=function(){for(var e=this.pos;/[\s\u00a0]/.test(this.string.charAt(this.pos));)++this.pos;return this.pos>e},Ye.prototype.skipToEnd=function(){this.pos=this.string.length},Ye.prototype.skipTo=function(e){var t=this.string.indexOf(e,this.pos);if(t>-1)return this.pos=t,!0},Ye.prototype.backUp=function(e){this.pos-=e},Ye.prototype.column=function(){return this.lastColumnPos0?null:(i&&!1!==t&&(this.pos+=i[0].length),i)}var o=r((function(e){return n?e.toLowerCase():e}),"cased");if(o(this.string.substr(this.pos,e.length))==o(e))return!1!==t&&(this.pos+=e.length),!0},Ye.prototype.current=function(){return this.string.slice(this.start,this.pos)},Ye.prototype.hideFirstChars=function(e,t){this.lineStart+=e;try{return t()}finally{this.lineStart-=e}},Ye.prototype.lookAhead=function(e){var t=this.lineOracle;return t&&t.lookAhead(e)},Ye.prototype.baseToken=function(){var e=this.lineOracle;return e&&e.baseToken(this.pos)},r(Je,"getLine"),r(Ze,"getBetween"),r(et,"getLines"),r(tt,"updateLineHeight"),r(nt,"lineNo"),r(rt,"lineAtHeight"),r(it,"isLine"),r(ot,"lineNumberFor"),r(at,"Pos"),r(st,"cmp"),r(lt,"equalCursorPos"),r(ut,"copyPos"),r(ct,"maxPos"),r(dt,"minPos"),r(ft,"clipLine"),r(pt,"clipPos"),r(ht,"clipToLen"),r(mt,"clipPosArray");var gt=r((function(e,t){this.state=e,this.lookAhead=t}),"SavedContext"),vt=r((function(e,t,n,r){this.state=t,this.doc=e,this.line=n,this.maxLookAhead=r||0,this.baseTokens=null,this.baseTokenPos=1}),"Context");function yt(e,t,n,i){var o=[e.state.modeGen],a={};Nt(e,t.text,e.doc.mode,n,(function(e,t){return o.push(e,t)}),a,i);for(var s=n.state,l=r((function(r){n.baseTokens=o;var i=e.state.overlays[r],l=1,u=0;n.state=!0,Nt(e,t.text,i.mode,n,(function(e,t){for(var n=l;ue&&o.splice(l,1,e,o[l+1],r),l+=2,u=Math.min(e,r)}if(t)if(i.opaque)o.splice(n,l-n,e,"overlay "+t),l=n+2;else for(;ne.options.maxHighlightLength&&Ke(e.doc.mode,r.state),o=yt(e,t,r);i&&(r.state=i),t.stateAfter=r.save(!i),t.styles=o.styles,o.classes?t.styleClasses=o.classes:t.styleClasses&&(t.styleClasses=null),n===e.doc.highlightFrontier&&(e.doc.modeFrontier=Math.max(e.doc.modeFrontier,++e.doc.highlightFrontier))}return t.styles}function Et(e,t,n){var r=e.doc,i=e.display;if(!r.mode.startState)return new vt(r,!0,t);var o=_t(e,t,n),a=o>r.first&&Je(r,o-1).stateAfter,s=a?vt.fromSaved(r,a,o):new vt(r,Xe(r.mode),o);return r.iter(o,t,(function(n){Tt(e,n.text,s);var r=s.line;n.stateAfter=r==t-1||r%5==0||r>=i.viewFrom&&rt.start)return o}throw new Error("Mode "+e.name+" failed to advance stream.")}vt.prototype.lookAhead=function(e){var t=this.doc.getLine(this.line+e);return null!=t&&e>this.maxLookAhead&&(this.maxLookAhead=e),t},vt.prototype.baseToken=function(e){if(!this.baseTokens)return null;for(;this.baseTokens[this.baseTokenPos]<=e;)this.baseTokenPos+=2;var t=this.baseTokens[this.baseTokenPos+1];return{type:t&&t.replace(/( |^)overlay .*/,""),size:this.baseTokens[this.baseTokenPos]-e}},vt.prototype.nextLine=function(){this.line++,this.maxLookAhead>0&&this.maxLookAhead--},vt.fromSaved=function(e,t,n){return t instanceof gt?new vt(e,Ke(e.mode,t.state),n,t.lookAhead):new vt(e,Ke(e.mode,t),n)},vt.prototype.save=function(e){var t=!1!==e?Ke(this.doc.mode,this.state):this.state;return this.maxLookAhead>0?new gt(t,this.maxLookAhead):t},r(yt,"highlightLine"),r(bt,"getLineStyles"),r(Et,"getContextBefore"),r(Tt,"processLine"),r(wt,"callBlankLine"),r(Ct,"readToken");var St=r((function(e,t,n){this.start=e.start,this.end=e.pos,this.string=e.current(),this.type=t||null,this.state=n}),"Token");function xt(e,t,n,r){var i,o,a=e.doc,s=a.mode,l=Je(a,(t=pt(a,t)).line),u=Et(e,t.line,n),c=new Ye(l.text,e.options.tabSize,u);for(r&&(o=[]);(r||c.pose.options.maxHighlightLength?(s=!1,a&&Tt(e,t,r,d.pos),d.pos=t.length,l=null):l=kt(Ct(n,d,r.state,f),o),f){var p=f[0].name;p&&(l="m-"+(l?p+" "+l:p))}if(!s||c!=l){for(;ua;--s){if(s<=o.first)return o.first;var l=Je(o,s-1),u=l.stateAfter;if(u&&(!n||s+(u instanceof gt?u.lookAhead:0)<=o.modeFrontier))return s;var c=V(l.text,null,e.options.tabSize);(null==i||r>c)&&(i=s-1,r=c)}return i}function Ot(e,t){if(e.modeFrontier=Math.min(e.modeFrontier,t),!(e.highlightFrontiern;r--){var i=Je(e,r).stateAfter;if(i&&(!(i instanceof gt)||r+i.lookAhead=t:o.to>t);(r||(r=[])).push(new Mt(a,o.from,s?null:o.to))}}return r}function Vt(e,t,n){var r;if(e)for(var i=0;i=t:o.to>t)||o.from==t&&"bookmark"==a.type&&(!n||o.marker.insertLeft)){var s=null==o.from||(a.inclusiveLeft?o.from<=t:o.from0&&s)for(var b=0;b0)){var c=[l,1],d=st(u.from,s.from),f=st(u.to,s.to);(d<0||!a.inclusiveLeft&&!d)&&c.push({from:u.from,to:s.from}),(f>0||!a.inclusiveRight&&!f)&&c.push({from:s.to,to:u.to}),i.splice.apply(i,c),l+=c.length-3}}return i}function qt(e){var t=e.markedSpans;if(t){for(var n=0;nt)&&(!n||Wt(n,o.marker)<0)&&(n=o.marker)}return n}function Jt(e,t,n,r,i){var o=Je(e,t),a=Dt&&o.markedSpans;if(a)for(var s=0;s=0&&d<=0||c<=0&&d>=0)&&(c<=0&&(l.marker.inclusiveRight&&i.inclusiveLeft?st(u.to,n)>=0:st(u.to,n)>0)||c>=0&&(l.marker.inclusiveRight&&i.inclusiveLeft?st(u.from,r)<=0:st(u.from,r)<0)))return!0}}}function Zt(e){for(var t;t=Qt(e);)e=t.find(-1,!0).line;return e}function en(e){for(var t;t=Xt(e);)e=t.find(1,!0).line;return e}function tn(e){for(var t,n;t=Xt(e);)e=t.find(1,!0).line,(n||(n=[])).push(e);return n}function nn(e,t){var n=Je(e,t),r=Zt(n);return n==r?t:nt(r)}function rn(e,t){if(t>e.lastLine())return t;var n,r=Je(e,t);if(!on(e,r))return t;for(;n=Xt(r);)r=n.find(1,!0).line;return nt(r)+1}function on(e,t){var n=Dt&&t.markedSpans;if(n)for(var r=void 0,i=0;it.maxLineLength&&(t.maxLineLength=n,t.maxLine=e)}))}r(Lt,"seeReadOnlySpans"),r(At,"seeCollapsedSpans"),r(Mt,"MarkedSpan"),r(Rt,"getMarkedSpanFor"),r(Ft,"removeMarkedSpan"),r(Pt,"addMarkedSpan"),r(jt,"markedSpansBefore"),r(Vt,"markedSpansAfter"),r(Ut,"stretchSpansOverChange"),r(Bt,"clearEmptySpans"),r($t,"removeReadOnlyRanges"),r(qt,"detachMarkedSpans"),r(Ht,"attachMarkedSpans"),r(Gt,"extraLeft"),r(zt,"extraRight"),r(Wt,"compareCollapsedMarkers"),r(Kt,"collapsedSpanAtSide"),r(Qt,"collapsedSpanAtStart"),r(Xt,"collapsedSpanAtEnd"),r(Yt,"collapsedSpanAround"),r(Jt,"conflictingCollapsedRange"),r(Zt,"visualLine"),r(en,"visualLineEnd"),r(tn,"visualLineContinued"),r(nn,"visualLineNo"),r(rn,"visualLineEndNo"),r(on,"lineIsHidden"),r(an,"lineIsHiddenInner"),r(sn,"heightAtLine"),r(ln,"lineLength"),r(un,"findMaxLine");var cn=r((function(e,t,n){this.text=e,Ht(this,t),this.height=n?n(this):1}),"Line");function dn(e,t,n,r){e.text=t,e.stateAfter&&(e.stateAfter=null),e.styles&&(e.styles=null),null!=e.order&&(e.order=null),qt(e),Ht(e,n);var i=r?r(e):1;i!=e.height&&tt(e,i)}function fn(e){e.parent=null,qt(e)}cn.prototype.lineNo=function(){return nt(this)},we(cn),r(dn,"updateLine"),r(fn,"cleanUpLine");var pn={},hn={};function mn(e,t){if(!e||/^\s*$/.test(e))return null;var n=t.addModeClass?hn:pn;return n[e]||(n[e]=e.replace(/\S+/g,"cm-$&"))}function gn(e,t){var n=D("span",null,null,u?"padding-right: .1px":null),r={pre:D("pre",[n],"CodeMirror-line"),content:n,col:0,pos:0,cm:e,trailingSpace:!1,splitSpaces:e.getOption("lineWrapping")};t.measure={};for(var i=0;i<=(t.rest?t.rest.length:0);i++){var o=i?t.rest[i-1]:t.line,a=void 0;r.pos=0,r.addToken=yn,Ae(e.display.measure)&&(a=pe(o,e.doc.direction))&&(r.addToken=En(r.addToken,a)),r.map=[],wn(o,r,bt(e,o,t!=e.display.externalMeasured&&nt(o))),o.styleClasses&&(o.styleClasses.bgClass&&(r.bgClass=R(o.styleClasses.bgClass,r.bgClass||"")),o.styleClasses.textClass&&(r.textClass=R(o.styleClasses.textClass,r.textClass||""))),0==r.map.length&&r.map.push(0,0,r.content.appendChild(Le(e.display.measure))),0==i?(t.measure.map=r.map,t.measure.cache={}):((t.measure.maps||(t.measure.maps=[])).push(r.map),(t.measure.caches||(t.measure.caches=[])).push({}))}if(u){var s=r.content.lastChild;(/\bcm-tab\b/.test(s.className)||s.querySelector&&s.querySelector(".cm-tab"))&&(r.content.className="cm-tab-wrap-hack")}return ye(e,"renderLine",e,t.line,r.pre),r.pre.className&&(r.textClass=R(r.pre.className,r.textClass||"")),r}function vn(e){var t=I("span","•","cm-invalidchar");return t.title="\\u"+e.charCodeAt(0).toString(16),t.setAttribute("aria-label",t.title),t}function yn(e,t,n,r,i,o,a){if(t){var u,c=e.splitSpaces?bn(t,e.trailingSpace):t,d=e.cm.state.specialChars,f=!1;if(d.test(t)){u=document.createDocumentFragment();for(var p=0;;){d.lastIndex=p;var h=d.exec(t),m=h?h.index-p:t.length-p;if(m){var g=document.createTextNode(c.slice(p,p+m));s&&l<9?u.appendChild(I("span",[g])):u.appendChild(g),e.map.push(e.pos,e.pos+m,g),e.col+=m,e.pos+=m}if(!h)break;p+=m+1;var v=void 0;if("\t"==h[0]){var y=e.cm.options.tabSize,b=y-e.col%y;(v=u.appendChild(I("span",Q(b),"cm-tab"))).setAttribute("role","presentation"),v.setAttribute("cm-text","\t"),e.col+=b}else"\r"==h[0]||"\n"==h[0]?((v=u.appendChild(I("span","\r"==h[0]?"␍":"␤","cm-invalidchar"))).setAttribute("cm-text",h[0]),e.col+=1):((v=e.cm.options.specialCharPlaceholder(h[0])).setAttribute("cm-text",h[0]),s&&l<9?u.appendChild(I("span",[v])):u.appendChild(v),e.col+=1);e.map.push(e.pos,e.pos+1,v),e.pos++}}else e.col+=t.length,u=document.createTextNode(c),e.map.push(e.pos,e.pos+t.length,u),s&&l<9&&(f=!0),e.pos+=t.length;if(e.trailingSpace=32==c.charCodeAt(t.length-1),n||r||i||f||o||a){var E=n||"";r&&(E+=r),i&&(E+=i);var T=I("span",[u],E,o);if(a)for(var w in a)a.hasOwnProperty(w)&&"style"!=w&&"class"!=w&&T.setAttribute(w,a[w]);return e.content.appendChild(T)}e.content.appendChild(u)}}function bn(e,t){if(e.length>1&&!/ /.test(e))return e;for(var n=t,r="",i=0;iu&&d.from<=u);f++);if(d.to>=c)return e(n,r,i,o,a,s,l);e(n,r.slice(0,d.to-u),i,o,null,s,l),o=null,r=r.slice(d.to-u),u=d.to}}}function Tn(e,t,n,r){var i=!r&&n.widgetNode;i&&e.map.push(e.pos,e.pos+t,i),!r&&e.cm.display.input.needsContentAttribute&&(i||(i=e.content.appendChild(document.createElement("span"))),i.setAttribute("cm-marker",n.id)),i&&(e.cm.display.input.setUneditable(i),e.content.appendChild(i)),e.pos+=t,e.trailingSpace=!1}function wn(e,t,n){var r=e.markedSpans,i=e.text,o=0;if(r)for(var a,s,l,u,c,d,f,p=i.length,h=0,m=1,g="",v=0;;){if(v==h){l=u=c=s="",f=null,d=null,v=1/0;for(var y=[],b=void 0,E=0;Eh||w.collapsed&&T.to==h&&T.from==h)){if(null!=T.to&&T.to!=h&&v>T.to&&(v=T.to,u=""),w.className&&(l+=" "+w.className),w.css&&(s=(s?s+";":"")+w.css),w.startStyle&&T.from==h&&(c+=" "+w.startStyle),w.endStyle&&T.to==v&&(b||(b=[])).push(w.endStyle,T.to),w.title&&((f||(f={})).title=w.title),w.attributes)for(var C in w.attributes)(f||(f={}))[C]=w.attributes[C];w.collapsed&&(!d||Wt(d.marker,w)<0)&&(d=T)}else T.from>h&&v>T.from&&(v=T.from)}if(b)for(var S=0;S=p)break;for(var k=Math.min(p,v);;){if(g){var N=h+g.length;if(!d){var _=N>k?g.slice(0,k-h):g;t.addToken(t,_,a?a+l:l,c,h+_.length==v?u:"",s,f)}if(N>=k){g=g.slice(k-h),h=k;break}h=N,c=""}g=i.slice(o,o=n[m++]),a=mn(n[m++],t.cm.options)}}else for(var O=1;O2&&o.push((l.bottom+u.top)/2-n.top)}}o.push(n.bottom-n.top)}}function Zn(e,t,n){if(e.line==t)return{map:e.measure.map,cache:e.measure.cache};if(e.rest){for(var r=0;rn)return{map:e.measure.maps[i],cache:e.measure.caches[i],before:!0}}}function er(e,t){var n=nt(t=Zt(t)),r=e.display.externalMeasured=new Cn(e.doc,t,n);r.lineN=n;var i=r.built=gn(e,r);return r.text=i.pre,O(e.display.lineMeasure,i.pre),r}function tr(e,t,n,r){return ir(e,rr(e,t),n,r)}function nr(e,t){if(t>=e.display.viewFrom&&t=n.lineN&&tt)&&(i=(o=l-s)-1,t>=l&&(a="right")),null!=i){if(r=e[u+2],s==l&&n==(r.insertLeft?"left":"right")&&(a=n),"left"==n&&0==i)for(;u&&e[u-2]==e[u-3]&&e[u-1].insertLeft;)r=e[2+(u-=3)],a="left";if("right"==n&&i==l-s)for(;u=0&&(n=e[i]).left==n.right;i--);return n}function ur(e,t,n,r){var i,o=sr(t.map,n,r),a=o.node,u=o.start,c=o.end,d=o.collapse;if(3==a.nodeType){for(var f=0;f<4;f++){for(;u&&ae(t.line.text.charAt(o.coverStart+u));)--u;for(;o.coverStart+c0&&(d=r="right"),i=e.options.lineWrapping&&(p=a.getClientRects()).length>1?p["right"==r?p.length-1:0]:a.getBoundingClientRect()}if(s&&l<9&&!u&&(!i||!i.left&&!i.right)){var h=a.parentNode.getClientRects()[0];i=h?{left:h.left,right:h.left+Dr(e.display),top:h.top,bottom:h.bottom}:ar}for(var m=i.top-t.rect.top,g=i.bottom-t.rect.top,v=(m+g)/2,y=t.view.measure.heights,b=0;b=i.text.length?(u=i.text.length,c="before"):u<=0&&(u=0,c="after"),!l)return s("before"==c?u-1:u,"before"==c);function d(e,t,n){return s(n?e-1:e,1==l[t].level!=n)}r(d,"getBidi");var f=de(l,u,c),p=ce,h=d(u,f,"before"==c);return null!=p&&(h.other=d(u,p,"before"!=c)),h}function Tr(e,t){var n=0;t=pt(e.doc,t),e.options.lineWrapping||(n=Dr(e.display)*t.ch);var r=Je(e.doc,t.line),i=sn(r)+zn(e.display);return{left:n,right:n,top:i,bottom:i+r.height}}function wr(e,t,n,r,i){var o=at(e,t,n);return o.xRel=i,r&&(o.outside=r),o}function Cr(e,t,n){var r=e.doc;if((n+=e.display.viewOffset)<0)return wr(r.first,0,null,-1,-1);var i=rt(r,n),o=r.first+r.size-1;if(i>o)return wr(r.first+r.size-1,Je(r,o).text.length,null,1,1);t<0&&(t=0);for(var a=Je(r,i);;){var s=Nr(e,a,i,t,n),l=Yt(a,s.ch+(s.xRel>0||s.outside>0?1:0));if(!l)return s;var u=l.find(1);if(u.line==i)return u;a=Je(r,i=u.line)}}function Sr(e,t,n,r){r-=gr(t);var i=t.text.length,o=le((function(t){return ir(e,n,t-1).bottom<=r}),i,0);return{begin:o,end:i=le((function(t){return ir(e,n,t).top>r}),o,i)}}function xr(e,t,n,r){return n||(n=rr(e,t)),Sr(e,t,n,vr(e,t,ir(e,n,r),"line").top)}function kr(e,t,n,r){return!(e.bottom<=n)&&(e.top>n||(r?e.left:e.right)>t)}function Nr(e,t,n,r,i){i-=sn(t);var o=rr(e,t),a=gr(t),s=0,l=t.text.length,u=!0,c=pe(t,e.doc.direction);if(c){var d=(e.options.lineWrapping?Or:_r)(e,t,n,o,c,r,i);s=(u=1!=d.level)?d.from:d.to-1,l=u?d.to:d.from-1}var f,p,h=null,m=null,g=le((function(t){var n=ir(e,o,t);return n.top+=a,n.bottom+=a,!!kr(n,r,i,!1)&&(n.top<=i&&n.left<=r&&(h=t,m=n),!0)}),s,l),v=!1;if(m){var y=r-m.left=E.bottom?1:0}return wr(n,g=se(t.text,g,1),p,v,r-f)}function _r(e,t,n,r,i,o,a){var s=le((function(s){var l=i[s],u=1!=l.level;return kr(Er(e,at(n,u?l.to:l.from,u?"before":"after"),"line",t,r),o,a,!0)}),0,i.length-1),l=i[s];if(s>0){var u=1!=l.level,c=Er(e,at(n,u?l.from:l.to,u?"after":"before"),"line",t,r);kr(c,o,a,!0)&&c.top>a&&(l=i[s-1])}return l}function Or(e,t,n,r,i,o,a){var s=Sr(e,t,r,a),l=s.begin,u=s.end;/\s/.test(t.text.charAt(u-1))&&u--;for(var c=null,d=null,f=0;f=u||p.to<=l)){var h=ir(e,r,1!=p.level?Math.min(u,p.to)-1:Math.max(l,p.from)).right,m=hm)&&(c=p,d=m)}}return c||(c=i[i.length-1]),c.fromu&&(c={from:c.from,to:u,level:c.level}),c}function Ir(e){if(null!=e.cachedTextHeight)return e.cachedTextHeight;if(null==or){or=I("pre",null,"CodeMirror-line-like");for(var t=0;t<49;++t)or.appendChild(document.createTextNode("x")),or.appendChild(I("br"));or.appendChild(document.createTextNode("x"))}O(e.measure,or);var n=or.offsetHeight/50;return n>3&&(e.cachedTextHeight=n),_(e.measure),n||1}function Dr(e){if(null!=e.cachedCharWidth)return e.cachedCharWidth;var t=I("span","xxxxxxxxxx"),n=I("pre",[t],"CodeMirror-line-like");O(e.measure,n);var r=t.getBoundingClientRect(),i=(r.right-r.left)/10;return i>2&&(e.cachedCharWidth=i),i||10}function Lr(e){for(var t=e.display,n={},r={},i=t.gutters.clientLeft,o=t.gutters.firstChild,a=0;o;o=o.nextSibling,++a){var s=e.display.gutterSpecs[a].className;n[s]=o.offsetLeft+o.clientLeft+i,r[s]=o.clientWidth}return{fixedPos:Ar(t),gutterTotalWidth:t.gutters.offsetWidth,gutterLeft:n,gutterWidth:r,wrapperWidth:t.wrapper.clientWidth}}function Ar(e){return e.scroller.getBoundingClientRect().left-e.sizer.getBoundingClientRect().left}function Mr(e){var t=Ir(e.display),n=e.options.lineWrapping,r=n&&Math.max(5,e.display.scroller.clientWidth/Dr(e.display)-3);return function(i){if(on(e.doc,i))return 0;var o=0;if(i.widgets)for(var a=0;a0&&(l=Je(e.doc,u.line).text).length==u.ch){var c=V(l,l.length,e.options.tabSize)-l.length;u=at(u.line,Math.max(0,Math.round((o-Kn(e.display).left)/Dr(e.display))-c))}return u}function Pr(e,t){if(t>=e.display.viewTo)return null;if((t-=e.display.viewFrom)<0)return null;for(var n=e.display.view,r=0;rt)&&(i.updateLineNumbers=t),e.curOp.viewChanged=!0,t>=i.viewTo)Dt&&nn(e.doc,t)i.viewFrom?Ur(e):(i.viewFrom+=r,i.viewTo+=r);else if(t<=i.viewFrom&&n>=i.viewTo)Ur(e);else if(t<=i.viewFrom){var o=Br(e,n,n+r,1);o?(i.view=i.view.slice(o.index),i.viewFrom=o.lineN,i.viewTo+=r):Ur(e)}else if(n>=i.viewTo){var a=Br(e,t,t,-1);a?(i.view=i.view.slice(0,a.index),i.viewTo=a.lineN):Ur(e)}else{var s=Br(e,t,t,-1),l=Br(e,n,n+r,1);s&&l?(i.view=i.view.slice(0,s.index).concat(Sn(e,s.lineN,l.lineN)).concat(i.view.slice(l.index)),i.viewTo+=r):Ur(e)}var u=i.externalMeasured;u&&(n=i.lineN&&t=r.viewTo)){var o=r.view[Pr(e,t)];if(null!=o.node){var a=o.changes||(o.changes=[]);-1==B(a,n)&&a.push(n)}}}function Ur(e){e.display.viewFrom=e.display.viewTo=e.doc.first,e.display.view=[],e.display.viewOffset=0}function Br(e,t,n,r){var i,o=Pr(e,t),a=e.display.view;if(!Dt||n==e.doc.first+e.doc.size)return{index:o,lineN:n};for(var s=e.display.viewFrom,l=0;l0){if(o==a.length-1)return null;i=s+a[o].size-t,o++}else i=s-t;t+=i,n+=i}for(;nn(e.doc,n)!=n;){if(o==(r<0?0:a.length-1))return null;n+=r*a[o-(r<0?1:0)].size,o+=r}return{index:o,lineN:n}}function $r(e,t,n){var r=e.display;0==r.view.length||t>=r.viewTo||n<=r.viewFrom?(r.view=Sn(e,t,n),r.viewFrom=t):(r.viewFrom>t?r.view=Sn(e,t,r.viewFrom).concat(r.view):r.viewFromn&&(r.view=r.view.slice(0,Pr(e,n)))),r.viewTo=n}function qr(e){for(var t=e.display.view,n=0,r=0;r=e.display.viewTo||l.to().line0?a:e.defaultCharWidth())+"px"}if(r.other){var s=n.appendChild(I("div"," ","CodeMirror-cursor CodeMirror-secondarycursor"));s.style.display="",s.style.left=r.other.left+"px",s.style.top=r.other.top+"px",s.style.height=.85*(r.other.bottom-r.other.top)+"px"}}function Wr(e,t){return e.top-t.top||e.left-t.left}function Kr(e,t,n){var i=e.display,o=e.doc,a=document.createDocumentFragment(),s=Kn(e.display),l=s.left,u=Math.max(i.sizerWidth,Xn(e)-i.sizer.offsetLeft)-s.right,c="ltr"==o.direction;function d(e,t,n,r){t<0&&(t=0),t=Math.round(t),r=Math.round(r),a.appendChild(I("div",null,"CodeMirror-selected","position: absolute; left: "+e+"px;\n top: "+t+"px; width: "+(null==n?u-e:n)+"px;\n height: "+(r-t)+"px"))}function f(t,n,i){var a,s,f=Je(o,t),p=f.text.length;function h(n,r){return br(e,at(t,n),"div",f,r)}function m(t,n,r){var i=xr(e,f,null,t),o="ltr"==n==("after"==r)?"left":"right";return h("after"==r?i.begin:i.end-(/\s/.test(f.text.charAt(i.end-1))?2:1),o)[o]}r(h,"coords"),r(m,"wrapX");var g=pe(f,o.direction);return ue(g,n||0,null==i?p:i,(function(e,t,r,o){var f="ltr"==r,v=h(e,f?"left":"right"),y=h(t-1,f?"right":"left"),b=null==n&&0==e,E=null==i&&t==p,T=0==o,w=!g||o==g.length-1;if(y.top-v.top<=3){var C=(c?E:b)&&w,S=(c?b:E)&&T?l:(f?v:y).left,x=C?u:(f?y:v).right;d(S,v.top,x-S,v.bottom)}else{var k,N,_,O;f?(k=c&&b&&T?l:v.left,N=c?u:m(e,r,"before"),_=c?l:m(t,r,"after"),O=c&&E&&w?u:y.right):(k=c?m(e,r,"before"):l,N=!c&&b&&T?u:v.right,_=!c&&E&&w?l:y.left,O=c?m(t,r,"after"):u),d(k,v.top,N-k,v.bottom),v.bottom0?t.blinker=setInterval((function(){e.hasFocus()||Zr(e),t.cursorDiv.style.visibility=(n=!n)?"":"hidden"}),e.options.cursorBlinkRate):e.options.cursorBlinkRate<0&&(t.cursorDiv.style.visibility="hidden")}}function Xr(e){e.hasFocus()||(e.display.input.focus(),e.state.focused||Jr(e))}function Yr(e){e.state.delayingBlurEvent=!0,setTimeout((function(){e.state.delayingBlurEvent&&(e.state.delayingBlurEvent=!1,e.state.focused&&Zr(e))}),100)}function Jr(e,t){e.state.delayingBlurEvent&&!e.state.draggingText&&(e.state.delayingBlurEvent=!1),"nocursor"!=e.options.readOnly&&(e.state.focused||(ye(e,"focus",e,t),e.state.focused=!0,M(e.display.wrapper,"CodeMirror-focused"),e.curOp||e.display.selForContextMenu==e.doc.sel||(e.display.input.reset(),u&&setTimeout((function(){return e.display.input.reset(!0)}),20)),e.display.input.receivedFocus()),Qr(e))}function Zr(e,t){e.state.delayingBlurEvent||(e.state.focused&&(ye(e,"blur",e,t),e.state.focused=!1,N(e.display.wrapper,"CodeMirror-focused")),clearInterval(e.display.blinker),setTimeout((function(){e.state.focused||(e.display.shift=!1)}),150))}function ei(e){for(var t=e.display,n=t.lineDiv.offsetTop,r=Math.max(0,t.scroller.getBoundingClientRect().top),i=t.lineDiv.getBoundingClientRect().top,o=0,a=0;a.005||m<-.005)&&(ie.display.sizerWidth){var v=Math.ceil(f/Dr(e.display));v>e.display.maxLineLength&&(e.display.maxLineLength=v,e.display.maxLine=u.line,e.display.maxLineChanged=!0)}}}Math.abs(o)>2&&(t.scroller.scrollTop+=o)}function ti(e){if(e.widgets)for(var t=0;t=a&&(o=rt(t,sn(Je(t,l))-e.wrapper.clientHeight),a=l)}return{from:o,to:Math.max(a,o+1)}}function ri(e,t){if(!be(e,"scrollCursorIntoView")){var n=e.display,r=n.sizer.getBoundingClientRect(),i=null;if(t.top+r.top<0?i=!0:t.bottom+r.top>(window.innerHeight||document.documentElement.clientHeight)&&(i=!1),null!=i&&!m){var o=I("div","​",null,"position: absolute;\n top: "+(t.top-n.viewOffset-zn(e.display))+"px;\n height: "+(t.bottom-t.top+Qn(e)+n.barHeight)+"px;\n left: "+t.left+"px; width: "+Math.max(2,t.right-t.left)+"px;");e.display.lineSpace.appendChild(o),o.scrollIntoView(i),e.display.lineSpace.removeChild(o)}}}function ii(e,t,n,r){var i;null==r&&(r=0),e.options.lineWrapping||t!=n||(n="before"==t.sticky?at(t.line,t.ch+1,"before"):t,t=t.ch?at(t.line,"before"==t.sticky?t.ch-1:t.ch,"after"):t);for(var o=0;o<5;o++){var a=!1,s=Er(e,t),l=n&&n!=t?Er(e,n):s,u=ai(e,i={left:Math.min(s.left,l.left),top:Math.min(s.top,l.top)-r,right:Math.max(s.left,l.left),bottom:Math.max(s.bottom,l.bottom)+r}),c=e.doc.scrollTop,d=e.doc.scrollLeft;if(null!=u.scrollTop&&(pi(e,u.scrollTop),Math.abs(e.doc.scrollTop-c)>1&&(a=!0)),null!=u.scrollLeft&&(mi(e,u.scrollLeft),Math.abs(e.doc.scrollLeft-d)>1&&(a=!0)),!a)break}return i}function oi(e,t){var n=ai(e,t);null!=n.scrollTop&&pi(e,n.scrollTop),null!=n.scrollLeft&&mi(e,n.scrollLeft)}function ai(e,t){var n=e.display,r=Ir(e.display);t.top<0&&(t.top=0);var i=e.curOp&&null!=e.curOp.scrollTop?e.curOp.scrollTop:n.scroller.scrollTop,o=Yn(e),a={};t.bottom-t.top>o&&(t.bottom=t.top+o);var s=e.doc.height+Wn(n),l=t.tops-r;if(t.topi+o){var c=Math.min(t.top,(u?s:t.bottom)-o);c!=i&&(a.scrollTop=c)}var d=e.options.fixedGutter?0:n.gutters.offsetWidth,f=e.curOp&&null!=e.curOp.scrollLeft?e.curOp.scrollLeft:n.scroller.scrollLeft-d,p=Xn(e)-n.gutters.offsetWidth,h=t.right-t.left>p;return h&&(t.right=t.left+p),t.left<10?a.scrollLeft=0:t.leftp+f-3&&(a.scrollLeft=t.right+(h?0:10)-p),a}function si(e,t){null!=t&&(di(e),e.curOp.scrollTop=(null==e.curOp.scrollTop?e.doc.scrollTop:e.curOp.scrollTop)+t)}function li(e){di(e);var t=e.getCursor();e.curOp.scrollToPos={from:t,to:t,margin:e.options.cursorScrollMargin}}function ui(e,t,n){null==t&&null==n||di(e),null!=t&&(e.curOp.scrollLeft=t),null!=n&&(e.curOp.scrollTop=n)}function ci(e,t){di(e),e.curOp.scrollToPos=t}function di(e){var t=e.curOp.scrollToPos;t&&(e.curOp.scrollToPos=null,fi(e,Tr(e,t.from),Tr(e,t.to),t.margin))}function fi(e,t,n,r){var i=ai(e,{left:Math.min(t.left,n.left),top:Math.min(t.top,n.top)-r,right:Math.max(t.right,n.right),bottom:Math.max(t.bottom,n.bottom)+r});ui(e,i.scrollLeft,i.scrollTop)}function pi(e,t){Math.abs(e.doc.scrollTop-t)<2||(n||Hi(e,{top:t}),hi(e,t,!0),n&&Hi(e),Fi(e,100))}function hi(e,t,n){t=Math.max(0,Math.min(e.display.scroller.scrollHeight-e.display.scroller.clientHeight,t)),(e.display.scroller.scrollTop!=t||n)&&(e.doc.scrollTop=t,e.display.scrollbars.setScrollTop(t),e.display.scroller.scrollTop!=t&&(e.display.scroller.scrollTop=t))}function mi(e,t,n,r){t=Math.max(0,Math.min(t,e.display.scroller.scrollWidth-e.display.scroller.clientWidth)),(n?t==e.doc.scrollLeft:Math.abs(e.doc.scrollLeft-t)<2)&&!r||(e.doc.scrollLeft=t,Ki(e),e.display.scroller.scrollLeft!=t&&(e.display.scroller.scrollLeft=t),e.display.scrollbars.setScrollLeft(t))}function gi(e){var t=e.display,n=t.gutters.offsetWidth,r=Math.round(e.doc.height+Wn(e.display));return{clientHeight:t.scroller.clientHeight,viewHeight:t.wrapper.clientHeight,scrollWidth:t.scroller.scrollWidth,clientWidth:t.scroller.clientWidth,viewWidth:t.wrapper.clientWidth,barLeft:e.options.fixedGutter?n:0,docHeight:r,scrollHeight:r+Qn(e)+t.barHeight,nativeBarWidth:t.nativeBarWidth,gutterWidth:n}}r(sr,"nodeAndOffsetInLineMap"),r(lr,"getUsefulRect"),r(ur,"measureCharInner"),r(cr,"maybeUpdateRectForZooming"),r(dr,"clearLineMeasurementCacheFor"),r(fr,"clearLineMeasurementCache"),r(pr,"clearCaches"),r(hr,"pageScrollX"),r(mr,"pageScrollY"),r(gr,"widgetTopHeight"),r(vr,"intoCoordSystem"),r(yr,"fromCoordSystem"),r(br,"charCoords"),r(Er,"cursorCoords"),r(Tr,"estimateCoords"),r(wr,"PosWithInfo"),r(Cr,"coordsChar"),r(Sr,"wrappedLineExtent"),r(xr,"wrappedLineExtentChar"),r(kr,"boxIsAfter"),r(Nr,"coordsCharInner"),r(_r,"coordsBidiPart"),r(Or,"coordsBidiPartWrapped"),r(Ir,"textHeight"),r(Dr,"charWidth"),r(Lr,"getDimensions"),r(Ar,"compensateForHScroll"),r(Mr,"estimateHeight"),r(Rr,"estimateLineHeights"),r(Fr,"posFromMouse"),r(Pr,"findViewIndex"),r(jr,"regChange"),r(Vr,"regLineChange"),r(Ur,"resetView"),r(Br,"viewCuttingPoint"),r($r,"adjustView"),r(qr,"countDirtyView"),r(Hr,"updateSelection"),r(Gr,"prepareSelection"),r(zr,"drawSelectionCursor"),r(Wr,"cmpCoords"),r(Kr,"drawSelectionRange"),r(Qr,"restartBlink"),r(Xr,"ensureFocus"),r(Yr,"delayBlurEvent"),r(Jr,"onFocus"),r(Zr,"onBlur"),r(ei,"updateHeightsInViewport"),r(ti,"updateWidgetHeight"),r(ni,"visibleLines"),r(ri,"maybeScrollWindow"),r(ii,"scrollPosIntoView"),r(oi,"scrollIntoView"),r(ai,"calculateScrollPos"),r(si,"addToScrollTop"),r(li,"ensureCursorVisible"),r(ui,"scrollToCoords"),r(ci,"scrollToRange"),r(di,"resolveScrollToPos"),r(fi,"scrollToCoordsRange"),r(pi,"updateScrollTop"),r(hi,"setScrollTop"),r(mi,"setScrollLeft"),r(gi,"measureForScrollbars");var vi=r((function(e,t,n){this.cm=n;var r=this.vert=I("div",[I("div",null,null,"min-width: 1px")],"CodeMirror-vscrollbar"),i=this.horiz=I("div",[I("div",null,null,"height: 100%; min-height: 1px")],"CodeMirror-hscrollbar");r.tabIndex=i.tabIndex=-1,e(r),e(i),me(r,"scroll",(function(){r.clientHeight&&t(r.scrollTop,"vertical")})),me(i,"scroll",(function(){i.clientWidth&&t(i.scrollLeft,"horizontal")})),this.checkedZeroWidth=!1,s&&l<8&&(this.horiz.style.minHeight=this.vert.style.minWidth="18px")}),"NativeScrollbars");vi.prototype.update=function(e){var t=e.scrollWidth>e.clientWidth+1,n=e.scrollHeight>e.clientHeight+1,r=e.nativeBarWidth;if(n){this.vert.style.display="block",this.vert.style.bottom=t?r+"px":"0";var i=e.viewHeight-(t?r:0);this.vert.firstChild.style.height=Math.max(0,e.scrollHeight-e.clientHeight+i)+"px"}else this.vert.scrollTop=0,this.vert.style.display="",this.vert.firstChild.style.height="0";if(t){this.horiz.style.display="block",this.horiz.style.right=n?r+"px":"0",this.horiz.style.left=e.barLeft+"px";var o=e.viewWidth-e.barLeft-(n?r:0);this.horiz.firstChild.style.width=Math.max(0,e.scrollWidth-e.clientWidth+o)+"px"}else this.horiz.style.display="",this.horiz.firstChild.style.width="0";return!this.checkedZeroWidth&&e.clientHeight>0&&(0==r&&this.zeroWidthHack(),this.checkedZeroWidth=!0),{right:n?r:0,bottom:t?r:0}},vi.prototype.setScrollLeft=function(e){this.horiz.scrollLeft!=e&&(this.horiz.scrollLeft=e),this.disableHoriz&&this.enableZeroWidthBar(this.horiz,this.disableHoriz,"horiz")},vi.prototype.setScrollTop=function(e){this.vert.scrollTop!=e&&(this.vert.scrollTop=e),this.disableVert&&this.enableZeroWidthBar(this.vert,this.disableVert,"vert")},vi.prototype.zeroWidthHack=function(){var e=b&&!h?"12px":"18px";this.horiz.style.height=this.vert.style.width=e,this.horiz.style.pointerEvents=this.vert.style.pointerEvents="none",this.disableHoriz=new U,this.disableVert=new U},vi.prototype.enableZeroWidthBar=function(e,t,n){function i(){var r=e.getBoundingClientRect();("vert"==n?document.elementFromPoint(r.right-1,(r.top+r.bottom)/2):document.elementFromPoint((r.right+r.left)/2,r.bottom-1))!=e?e.style.pointerEvents="none":t.set(1e3,i)}e.style.pointerEvents="auto",r(i,"maybeDisable"),t.set(1e3,i)},vi.prototype.clear=function(){var e=this.horiz.parentNode;e.removeChild(this.horiz),e.removeChild(this.vert)};var yi=r((function(){}),"NullScrollbars");function bi(e,t){t||(t=gi(e));var n=e.display.barWidth,r=e.display.barHeight;Ei(e,t);for(var i=0;i<4&&n!=e.display.barWidth||r!=e.display.barHeight;i++)n!=e.display.barWidth&&e.options.lineWrapping&&ei(e),Ei(e,gi(e)),n=e.display.barWidth,r=e.display.barHeight}function Ei(e,t){var n=e.display,r=n.scrollbars.update(t);n.sizer.style.paddingRight=(n.barWidth=r.right)+"px",n.sizer.style.paddingBottom=(n.barHeight=r.bottom)+"px",n.heightForcer.style.borderBottom=r.bottom+"px solid transparent",r.right&&r.bottom?(n.scrollbarFiller.style.display="block",n.scrollbarFiller.style.height=r.bottom+"px",n.scrollbarFiller.style.width=r.right+"px"):n.scrollbarFiller.style.display="",r.bottom&&e.options.coverGutterNextToScrollbar&&e.options.fixedGutter?(n.gutterFiller.style.display="block",n.gutterFiller.style.height=r.bottom+"px",n.gutterFiller.style.width=t.gutterWidth+"px"):n.gutterFiller.style.display=""}yi.prototype.update=function(){return{bottom:0,right:0}},yi.prototype.setScrollLeft=function(){},yi.prototype.setScrollTop=function(){},yi.prototype.clear=function(){},r(bi,"updateScrollbars"),r(Ei,"updateScrollbarsInner");var Ti={native:vi,null:yi};function wi(e){e.display.scrollbars&&(e.display.scrollbars.clear(),e.display.scrollbars.addClass&&N(e.display.wrapper,e.display.scrollbars.addClass)),e.display.scrollbars=new Ti[e.options.scrollbarStyle]((function(t){e.display.wrapper.insertBefore(t,e.display.scrollbarFiller),me(t,"mousedown",(function(){e.state.focused&&setTimeout((function(){return e.display.input.focus()}),0)})),t.setAttribute("cm-not-content","true")}),(function(t,n){"horizontal"==n?mi(e,t):pi(e,t)}),e),e.display.scrollbars.addClass&&M(e.display.wrapper,e.display.scrollbars.addClass)}r(wi,"initScrollbars");var Ci=0;function Si(e){e.curOp={cm:e,viewChanged:!1,startHeight:e.doc.height,forceUpdate:!1,updateInput:0,typing:!1,changeObjs:null,cursorActivityHandlers:null,cursorActivityCalled:0,selectionChanged:!1,updateMaxLine:!1,scrollLeft:null,scrollTop:null,scrollToPos:null,focus:!1,id:++Ci,markArrays:null},kn(e.curOp)}function xi(e){var t=e.curOp;t&&_n(t,(function(e){for(var t=0;t=n.viewTo)||n.maxLineChanged&&t.options.lineWrapping,e.update=e.mustUpdate&&new ji(t,e.mustUpdate&&{top:e.scrollTop,ensure:e.scrollToPos},e.forceUpdate)}function _i(e){e.updatedDisplay=e.mustUpdate&&$i(e.cm,e.update)}function Oi(e){var t=e.cm,n=t.display;e.updatedDisplay&&ei(t),e.barMeasure=gi(t),n.maxLineChanged&&!t.options.lineWrapping&&(e.adjustWidthTo=tr(t,n.maxLine,n.maxLine.text.length).left+3,t.display.sizerWidth=e.adjustWidthTo,e.barMeasure.scrollWidth=Math.max(n.scroller.clientWidth,n.sizer.offsetLeft+e.adjustWidthTo+Qn(t)+t.display.barWidth),e.maxScrollLeft=Math.max(0,n.sizer.offsetLeft+e.adjustWidthTo-Xn(t))),(e.updatedDisplay||e.selectionChanged)&&(e.preparedSelection=n.input.prepareSelection())}function Ii(e){var t=e.cm;null!=e.adjustWidthTo&&(t.display.sizer.style.minWidth=e.adjustWidthTo+"px",e.maxScrollLeft=e.display.viewTo)){var n=+new Date+e.options.workTime,r=Et(e,t.highlightFrontier),i=[];t.iter(r.line,Math.min(t.first+t.size,e.display.viewTo+500),(function(o){if(r.line>=e.display.viewFrom){var a=o.styles,s=o.text.length>e.options.maxHighlightLength?Ke(t.mode,r.state):null,l=yt(e,o,r,!0);s&&(r.state=s),o.styles=l.styles;var u=o.styleClasses,c=l.classes;c?o.styleClasses=c:u&&(o.styleClasses=null);for(var d=!a||a.length!=o.styles.length||u!=c&&(!u||!c||u.bgClass!=c.bgClass||u.textClass!=c.textClass),f=0;!d&&fn)return Fi(e,e.options.workDelay),!0})),t.highlightFrontier=r.line,t.modeFrontier=Math.max(t.modeFrontier,r.line),i.length&&Li(e,(function(){for(var t=0;t=n.viewFrom&&t.visible.to<=n.viewTo&&(null==n.updateLineNumbers||n.updateLineNumbers>=n.viewTo)&&n.renderedView==n.view&&0==qr(e))return!1;Qi(e)&&(Ur(e),t.dims=Lr(e));var i=r.first+r.size,o=Math.max(t.visible.from-e.options.viewportMargin,r.first),a=Math.min(i,t.visible.to+e.options.viewportMargin);n.viewFroma&&n.viewTo-a<20&&(a=Math.min(i,n.viewTo)),Dt&&(o=nn(e.doc,o),a=rn(e.doc,a));var s=o!=n.viewFrom||a!=n.viewTo||n.lastWrapHeight!=t.wrapperHeight||n.lastWrapWidth!=t.wrapperWidth;$r(e,o,a),n.viewOffset=sn(Je(e.doc,n.viewFrom)),e.display.mover.style.top=n.viewOffset+"px";var l=qr(e);if(!s&&0==l&&!t.force&&n.renderedView==n.view&&(null==n.updateLineNumbers||n.updateLineNumbers>=n.viewTo))return!1;var u=Ui(e);return l>4&&(n.lineDiv.style.display="none"),Gi(e,n.updateLineNumbers,t.dims),l>4&&(n.lineDiv.style.display=""),n.renderedView=n.view,Bi(u),_(n.cursorDiv),_(n.selectionDiv),n.gutters.style.height=n.sizer.style.minHeight=0,s&&(n.lastWrapHeight=t.wrapperHeight,n.lastWrapWidth=t.wrapperWidth,Fi(e,400)),n.updateLineNumbers=null,!0}function qi(e,t){for(var n=t.viewport,r=!0;;r=!1){if(r&&e.options.lineWrapping&&t.oldDisplayWidth!=Xn(e))r&&(t.visible=ni(e.display,e.doc,n));else if(n&&null!=n.top&&(n={top:Math.min(e.doc.height+Wn(e.display)-Yn(e),n.top)}),t.visible=ni(e.display,e.doc,n),t.visible.from>=e.display.viewFrom&&t.visible.to<=e.display.viewTo)break;if(!$i(e,t))break;ei(e);var i=gi(e);Hr(e),bi(e,i),Wi(e,i),t.force=!1}t.signal(e,"update",e),e.display.viewFrom==e.display.reportedViewFrom&&e.display.viewTo==e.display.reportedViewTo||(t.signal(e,"viewportChange",e,e.display.viewFrom,e.display.viewTo),e.display.reportedViewFrom=e.display.viewFrom,e.display.reportedViewTo=e.display.viewTo)}function Hi(e,t){var n=new ji(e,t);if($i(e,n)){ei(e),qi(e,n);var r=gi(e);Hr(e),bi(e,r),Wi(e,r),n.finish()}}function Gi(e,t,n){var i=e.display,o=e.options.lineNumbers,a=i.lineDiv,s=a.firstChild;function l(t){var n=t.nextSibling;return u&&b&&e.display.currentWheelTarget==t?t.style.display="none":t.parentNode.removeChild(t),n}r(l,"rm");for(var c=i.view,d=i.viewFrom,f=0;f-1&&(h=!1),Ln(e,p,d,n)),h&&(_(p.lineNumber),p.lineNumber.appendChild(document.createTextNode(ot(e.options,d)))),s=p.node.nextSibling}else{var m=Un(e,p,d,n);a.insertBefore(m,s)}d+=p.size}for(;s;)s=l(s)}function zi(e){var t=e.gutters.offsetWidth;e.sizer.style.marginLeft=t+"px",In(e,"gutterChanged",e)}function Wi(e,t){e.display.sizer.style.minHeight=t.docHeight+"px",e.display.heightForcer.style.top=t.docHeight+"px",e.display.gutters.style.height=t.docHeight+e.display.barHeight+Qn(e)+"px"}function Ki(e){var t=e.display,n=t.view;if(t.alignWidgets||t.gutters.firstChild&&e.options.fixedGutter){for(var r=Ar(t)-t.scroller.scrollLeft+e.doc.scrollLeft,i=t.gutters.offsetWidth,o=r+"px",a=0;al.clientWidth,d=l.scrollHeight>l.clientHeight;if(i&&c||o&&d){if(o&&b&&u)e:for(var p=t.target,h=s.view;p!=l;p=p.parentNode)for(var m=0;m=0&&st(e,r.to())<=0)return n}return-1};var ao=r((function(e,t){this.anchor=e,this.head=t}),"Range");function so(e,t,n){var r=e&&e.options.selectionsMayTouch,i=t[n];t.sort((function(e,t){return st(e.from(),t.from())})),n=B(t,i);for(var o=1;o0:l>=0){var u=dt(s.from(),a.from()),c=ct(s.to(),a.to()),d=s.empty()?a.from()==a.head:s.from()==s.head;o<=n&&--n,t.splice(--o,2,new ao(d?c:u,d?u:c))}}return new oo(t,n)}function lo(e,t){return new oo([new ao(e,t||e)],0)}function uo(e){return e.text?at(e.from.line+e.text.length-1,X(e.text).length+(1==e.text.length?e.from.ch:0)):e.to}function co(e,t){if(st(e,t.from)<0)return e;if(st(e,t.to)<=0)return uo(t);var n=e.line+t.text.length-(t.to.line-t.from.line)-1,r=e.ch;return e.line==t.to.line&&(r+=uo(t).ch-t.to.ch),at(n,r)}function fo(e,t){for(var n=[],r=0;r1&&e.remove(l.line+1,m-1),e.insert(l.line+1,y)}In(e,"change",e,t)}function bo(e,t,n){function i(e,r,o){if(e.linked)for(var a=0;a1&&!e.done[e.done.length-2].ranges?(e.done.pop(),X(e.done)):void 0}function No(e,t,n,r){var i=e.history;i.undone.length=0;var o,a,s=+new Date;if((i.lastOp==r||i.lastOrigin==t.origin&&t.origin&&("+"==t.origin.charAt(0)&&i.lastModTime>s-(e.cm?e.cm.options.historyEventDelay:500)||"*"==t.origin.charAt(0)))&&(o=ko(i,i.lastOp==r)))a=X(o.changes),0==st(t.from,t.to)&&0==st(t.from,a.to)?a.to=uo(t):o.changes.push(So(e,t));else{var l=X(i.done);for(l&&l.ranges||Io(e.sel,i.done),o={changes:[So(e,t)],generation:i.generation},i.done.push(o);i.done.length>i.undoDepth;)i.done.shift(),i.done[0].ranges||i.done.shift()}i.done.push(n),i.generation=++i.maxGeneration,i.lastModTime=i.lastSelTime=s,i.lastOp=i.lastSelOp=r,i.lastOrigin=i.lastSelOrigin=t.origin,a||ye(e,"historyAdded")}function _o(e,t,n,r){var i=t.charAt(0);return"*"==i||"+"==i&&n.ranges.length==r.ranges.length&&n.somethingSelected()==r.somethingSelected()&&new Date-e.history.lastSelTime<=(e.cm?e.cm.options.historyEventDelay:500)}function Oo(e,t,n,r){var i=e.history,o=r&&r.origin;n==i.lastSelOp||o&&i.lastSelOrigin==o&&(i.lastModTime==i.lastSelTime&&i.lastOrigin==o||_o(e,o,X(i.done),t))?i.done[i.done.length-1]=t:Io(t,i.done),i.lastSelTime=+new Date,i.lastSelOrigin=o,i.lastSelOp=n,r&&!1!==r.clearRedo&&xo(i.undone)}function Io(e,t){var n=X(t);n&&n.ranges&&n.equals(e)||t.push(e)}function Do(e,t,n,r){var i=t["spans_"+e.id],o=0;e.iter(Math.max(e.first,n),Math.min(e.first+e.size,r),(function(n){n.markedSpans&&((i||(i=t["spans_"+e.id]={}))[o]=n.markedSpans),++o}))}function Lo(e){if(!e)return null;for(var t,n=0;n-1&&(X(s)[d]=u[d],delete u[d])}}}return r}function Fo(e,t,n,r){if(r){var i=e.anchor;if(n){var o=st(t,i)<0;o!=st(n,i)<0?(i=t,t=n):o!=st(t,n)<0&&(t=n)}return new ao(i,t)}return new ao(n||t,t)}function Po(e,t,n,r,i){null==i&&(i=e.cm&&(e.cm.display.shift||e.extend)),qo(e,new oo([Fo(e.sel.primary(),t,n,i)],0),r)}function jo(e,t,n){for(var r=[],i=e.cm&&(e.cm.display.shift||e.extend),o=0;o=t.ch:s.to>t.ch))){if(i&&(ye(l,"beforeCursorEnter"),l.explicitlyCleared)){if(o.markedSpans){--a;continue}break}if(!l.atomic)continue;if(n){var d=l.find(r<0?1:-1),f=void 0;if((r<0?c:u)&&(d=Xo(e,d,-r,d&&d.line==t.line?o:null)),d&&d.line==t.line&&(f=st(d,n))&&(r<0?f<0:f>0))return Ko(e,d,t,r,i)}var p=l.find(r<0?-1:1);return(r<0?u:c)&&(p=Xo(e,p,r,p.line==t.line?o:null)),p?Ko(e,p,t,r,i):null}}return t}function Qo(e,t,n,r,i){var o=r||1;return Ko(e,t,n,o,i)||!i&&Ko(e,t,n,o,!0)||Ko(e,t,n,-o,i)||!i&&Ko(e,t,n,-o,!0)||(e.cantEdit=!0,at(e.first,0))}function Xo(e,t,n,r){return n<0&&0==t.ch?t.line>e.first?pt(e,at(t.line-1)):null:n>0&&t.ch==(r||Je(e,t.line)).text.length?t.line=0;--i)ea(e,{from:r[i].from,to:r[i].to,text:i?[""]:t.text,origin:t.origin});else ea(e,t)}}function ea(e,t){if(1!=t.text.length||""!=t.text[0]||0!=st(t.from,t.to)){var n=fo(e,t);No(e,t,n,e.cm?e.cm.curOp.id:NaN),ra(e,t,n,Ut(e,t));var r=[];bo(e,(function(e,n){n||-1!=B(r,e.history)||(la(e.history,t),r.push(e.history)),ra(e,t,null,Ut(e,t))}))}}function ta(e,t,n){var i=e.cm&&e.cm.state.suppressEdits;if(!i||n){for(var o,a=e.history,s=e.sel,l="undo"==t?a.done:a.undone,u="undo"==t?a.undone:a.done,c=0;c=0;--h){var m=p(h);if(m)return m.v}}}}function na(e,t){if(0!=t&&(e.first+=t,e.sel=new oo(Y(e.sel.ranges,(function(e){return new ao(at(e.anchor.line+t,e.anchor.ch),at(e.head.line+t,e.head.ch))})),e.sel.primIndex),e.cm)){jr(e.cm,e.first,e.first-t,t);for(var n=e.cm.display,r=n.viewFrom;re.lastLine())){if(t.from.lineo&&(t={from:t.from,to:at(o,Je(e,o).text.length),text:[t.text[0]],origin:t.origin}),t.removed=Ze(e,t.from,t.to),n||(n=fo(e,t)),e.cm?ia(e.cm,t,r):yo(e,t,r),Ho(e,n,H),e.cantEdit&&Qo(e,at(e.firstLine(),0))&&(e.cantEdit=!1)}}function ia(e,t,n){var r=e.doc,i=e.display,o=t.from,a=t.to,s=!1,l=o.line;e.options.lineWrapping||(l=nt(Zt(Je(r,o.line))),r.iter(l,a.line+1,(function(e){if(e==i.maxLine)return s=!0,!0}))),r.sel.contains(t.from,t.to)>-1&&Ee(e),yo(r,t,n,Mr(e)),e.options.lineWrapping||(r.iter(l,o.line+t.text.length,(function(e){var t=ln(e);t>i.maxLineLength&&(i.maxLine=e,i.maxLineLength=t,i.maxLineChanged=!0,s=!1)})),s&&(e.curOp.updateMaxLine=!0)),Ot(r,o.line),Fi(e,400);var u=t.text.length-(a.line-o.line)-1;t.full?jr(e):o.line!=a.line||1!=t.text.length||vo(e.doc,t)?jr(e,o.line,a.line+1,u):Vr(e,o.line,"text");var c=Te(e,"changes"),d=Te(e,"change");if(d||c){var f={from:o,to:a,text:t.text,removed:t.removed,origin:t.origin};d&&In(e,"change",e,f),c&&(e.curOp.changeObjs||(e.curOp.changeObjs=[])).push(f)}e.display.selForContextMenu=null}function oa(e,t,n,r,i){var o;r||(r=n),st(r,n)<0&&(n=(o=[r,n])[0],r=o[1]),"string"==typeof t&&(t=e.splitLines(t)),Zo(e,{from:n,to:r,text:t,origin:i})}function aa(e,t,n,r){n1||!(this.children[0]instanceof ca))){var s=[];this.collapse(s),this.children=[new ca(s)],this.children[0].parent=this}},collapse:function(e){for(var t=0;t50){for(var a=i.lines.length%25+25,s=a;s10);e.parent.maybeSpill()}},iterN:function(e,t,n){for(var r=0;r0||0==a&&!1!==o.clearWhenEmpty)return o;if(o.replacedWith&&(o.collapsed=!0,o.widgetNode=D("span",[o.replacedWith],"CodeMirror-widget"),r.handleMouseEvents||o.widgetNode.setAttribute("cm-ignore-events","true"),r.insertLeft&&(o.widgetNode.insertLeft=!0)),o.collapsed){if(Jt(e,t.line,t,n,o)||t.line!=n.line&&Jt(e,n.line,t,n,o))throw new Error("Inserting collapsed marker partially overlapping an existing one");At()}o.addToHistory&&No(e,{from:t,to:n,origin:"markText"},e.sel,NaN);var s,l=t.line,u=e.cm;if(e.iter(l,n.line+1,(function(r){u&&o.collapsed&&!u.options.lineWrapping&&Zt(r)==u.display.maxLine&&(s=!0),o.collapsed&&l!=t.line&&tt(r,0),Pt(r,new Mt(o,l==t.line?t.ch:null,l==n.line?n.ch:null),e.cm&&e.cm.curOp),++l})),o.collapsed&&e.iter(t.line,n.line+1,(function(t){on(e,t)&&tt(t,0)})),o.clearOnEnter&&me(o,"beforeCursorEnter",(function(){return o.clear()})),o.readOnly&&(Lt(),(e.history.done.length||e.history.undone.length)&&e.clearHistory()),o.collapsed&&(o.id=++ma,o.atomic=!0),u){if(s&&(u.curOp.updateMaxLine=!0),o.collapsed)jr(u,t.line,n.line+1);else if(o.className||o.startStyle||o.endStyle||o.css||o.attributes||o.title)for(var c=t.line;c<=n.line;c++)Vr(u,c,"text");o.atomic&&zo(u.doc),In(u,"markerAdded",u,o)}return o}ga.prototype.clear=function(){if(!this.explicitlyCleared){var e=this.doc.cm,t=e&&!e.curOp;if(t&&Si(e),Te(this,"clear")){var n=this.find();n&&In(this,"clear",n.from,n.to)}for(var r=null,i=null,o=0;oe.display.maxLineLength&&(e.display.maxLine=u,e.display.maxLineLength=c,e.display.maxLineChanged=!0)}null!=r&&e&&this.collapsed&&jr(e,r,i+1),this.lines.length=0,this.explicitlyCleared=!0,this.atomic&&this.doc.cantEdit&&(this.doc.cantEdit=!1,e&&zo(e.doc)),e&&In(e,"markerCleared",e,this,r,i),t&&xi(e),this.parent&&this.parent.clear()}},ga.prototype.find=function(e,t){var n,r;null==e&&"bookmark"==this.type&&(e=1);for(var i=0;i=0;l--)Zo(this,r[l]);s?$o(this,s):this.cm&&li(this.cm)})),undo:Ri((function(){ta(this,"undo")})),redo:Ri((function(){ta(this,"redo")})),undoSelection:Ri((function(){ta(this,"undo",!0)})),redoSelection:Ri((function(){ta(this,"redo",!0)})),setExtending:function(e){this.extend=e},getExtending:function(){return this.extend},historySize:function(){for(var e=this.history,t=0,n=0,r=0;r=e.ch)&&t.push(i.marker.parent||i.marker)}return t},findMarks:function(e,t,n){e=pt(this,e),t=pt(this,t);var r=[],i=e.line;return this.iter(e.line,t.line+1,(function(o){var a=o.markedSpans;if(a)for(var s=0;s=l.to||null==l.from&&i!=e.line||null!=l.from&&i==t.line&&l.from>=t.ch||n&&!n(l.marker)||r.push(l.marker.parent||l.marker)}++i})),r},getAllMarks:function(){var e=[];return this.iter((function(t){var n=t.markedSpans;if(n)for(var r=0;re)return t=e,!0;e-=o,++n})),pt(this,at(n,t))},indexFromPos:function(e){var t=(e=pt(this,e)).ch;if(e.linet&&(t=e.from),null!=e.to&&e.to-1)return t.state.draggingText(e),void setTimeout((function(){return t.display.input.focus()}),20);try{var f=e.dataTransfer.getData("Text");if(f){var p;if(t.state.draggingText&&!t.state.draggingText.copy&&(p=t.listSelections()),Ho(t.doc,lo(n,n)),p)for(var h=0;h=0;t--)oa(e.doc,"",r[t].from,r[t].to,"+delete");li(e)}))}function Ka(e,t,n){var r=se(e.text,t+n,n);return r<0||r>e.text.length?null:r}function Qa(e,t,n){var r=Ka(e,t.ch,n);return null==r?null:new at(t.line,r,n<0?"after":"before")}function Xa(e,t,n,r,i){if(e){"rtl"==t.doc.direction&&(i=-i);var o=pe(n,t.doc.direction);if(o){var a,s=i<0?X(o):o[0],l=i<0==(1==s.level)?"after":"before";if(s.level>0||"rtl"==t.doc.direction){var u=rr(t,n);a=i<0?n.text.length-1:0;var c=ir(t,u,a).top;a=le((function(e){return ir(t,u,e).top==c}),i<0==(1==s.level)?s.from:s.to-1,a),"before"==l&&(a=Ka(n,a,1))}else a=i<0?s.to:s.from;return new at(r,a,l)}}return new at(r,i<0?n.text.length:0,i<0?"before":"after")}function Ya(e,t,n,i){var o=pe(t,e.doc.direction);if(!o)return Qa(t,n,i);n.ch>=t.text.length?(n.ch=t.text.length,n.sticky="before"):n.ch<=0&&(n.ch=0,n.sticky="after");var a=de(o,n.ch,n.sticky),s=o[a];if("ltr"==e.doc.direction&&s.level%2==0&&(i>0?s.to>n.ch:s.from=s.from&&p>=d.begin)){var h=f?"before":"after";return new at(n.line,p,h)}}var m=r((function(e,t,i){for(var a=r((function(e,t){return t?new at(n.line,u(e,1),"before"):new at(n.line,e,"after")}),"getRes");e>=0&&e0==(1!=s.level),c=l?i.begin:u(i.end,-1);if(s.from<=c&&c0?d.end:u(d.begin,-1);return null==v||i>0&&v==t.text.length||!(g=m(i>0?0:o.length-1,i,c(v)))?null:g}Va.basic={Left:"goCharLeft",Right:"goCharRight",Up:"goLineUp",Down:"goLineDown",End:"goLineEnd",Home:"goLineStartSmart",PageUp:"goPageUp",PageDown:"goPageDown",Delete:"delCharAfter",Backspace:"delCharBefore","Shift-Backspace":"delCharBefore",Tab:"defaultTab","Shift-Tab":"indentAuto",Enter:"newlineAndIndent",Insert:"toggleOverwrite",Esc:"singleSelection"},Va.pcDefault={"Ctrl-A":"selectAll","Ctrl-D":"deleteLine","Ctrl-Z":"undo","Shift-Ctrl-Z":"redo","Ctrl-Y":"redo","Ctrl-Home":"goDocStart","Ctrl-End":"goDocEnd","Ctrl-Up":"goLineUp","Ctrl-Down":"goLineDown","Ctrl-Left":"goGroupLeft","Ctrl-Right":"goGroupRight","Alt-Left":"goLineStart","Alt-Right":"goLineEnd","Ctrl-Backspace":"delGroupBefore","Ctrl-Delete":"delGroupAfter","Ctrl-S":"save","Ctrl-F":"find","Ctrl-G":"findNext","Shift-Ctrl-G":"findPrev","Shift-Ctrl-F":"replace","Shift-Ctrl-R":"replaceAll","Ctrl-[":"indentLess","Ctrl-]":"indentMore","Ctrl-U":"undoSelection","Shift-Ctrl-U":"redoSelection","Alt-U":"redoSelection",fallthrough:"basic"},Va.emacsy={"Ctrl-F":"goCharRight","Ctrl-B":"goCharLeft","Ctrl-P":"goLineUp","Ctrl-N":"goLineDown","Ctrl-A":"goLineStart","Ctrl-E":"goLineEnd","Ctrl-V":"goPageDown","Shift-Ctrl-V":"goPageUp","Ctrl-D":"delCharAfter","Ctrl-H":"delCharBefore","Alt-Backspace":"delWordBefore","Ctrl-K":"killLine","Ctrl-T":"transposeChars","Ctrl-O":"openLine"},Va.macDefault={"Cmd-A":"selectAll","Cmd-D":"deleteLine","Cmd-Z":"undo","Shift-Cmd-Z":"redo","Cmd-Y":"redo","Cmd-Home":"goDocStart","Cmd-Up":"goDocStart","Cmd-End":"goDocEnd","Cmd-Down":"goDocEnd","Alt-Left":"goGroupLeft","Alt-Right":"goGroupRight","Cmd-Left":"goLineLeft","Cmd-Right":"goLineRight","Alt-Backspace":"delGroupBefore","Ctrl-Alt-Backspace":"delGroupAfter","Alt-Delete":"delGroupAfter","Cmd-S":"save","Cmd-F":"find","Cmd-G":"findNext","Shift-Cmd-G":"findPrev","Cmd-Alt-F":"replace","Shift-Cmd-Alt-F":"replaceAll","Cmd-[":"indentLess","Cmd-]":"indentMore","Cmd-Backspace":"delWrappedLineLeft","Cmd-Delete":"delWrappedLineRight","Cmd-U":"undoSelection","Shift-Cmd-U":"redoSelection","Ctrl-Up":"goDocStart","Ctrl-Down":"goDocEnd",fallthrough:["basic","emacsy"]},Va.default=b?Va.macDefault:Va.pcDefault,r(Ua,"normalizeKeyName"),r(Ba,"normalizeKeyMap"),r($a,"lookupKey"),r(qa,"isModifierKey"),r(Ha,"addModifierNames"),r(Ga,"keyName"),r(za,"getKeyMap"),r(Wa,"deleteNearSelection"),r(Ka,"moveCharLogically"),r(Qa,"moveLogically"),r(Xa,"endOfLine"),r(Ya,"moveVisually");var Ja={selectAll:Yo,singleSelection:function(e){return e.setSelection(e.getCursor("anchor"),e.getCursor("head"),H)},killLine:function(e){return Wa(e,(function(t){if(t.empty()){var n=Je(e.doc,t.head.line).text.length;return t.head.ch==n&&t.head.line0)i=new at(i.line,i.ch+1),e.replaceRange(o.charAt(i.ch-1)+o.charAt(i.ch-2),at(i.line,i.ch-2),i,"+transpose");else if(i.line>e.doc.first){var a=Je(e.doc,i.line-1).text;a&&(i=new at(i.line,1),e.replaceRange(o.charAt(0)+e.doc.lineSeparator()+a.charAt(a.length-1),at(i.line-1,a.length-1),i,"+transpose"))}n.push(new ao(i,i))}e.setSelections(n)}))},newlineAndIndent:function(e){return Li(e,(function(){for(var t=e.listSelections(),n=t.length-1;n>=0;n--)e.replaceRange(e.doc.lineSeparator(),t[n].anchor,t[n].head,"+input");t=e.listSelections();for(var r=0;r-1&&(st((i=a.ranges[i]).from(),t)<0||t.xRel>0)&&(st(i.to(),t)>0||t.xRel<0)?Cs(e,r,t,o):xs(e,r,t,o)}function Cs(e,t,n,i){var o=e.display,a=!1,c=Ai(e,(function(t){u&&(o.scroller.draggable=!1),e.state.draggingText=!1,e.state.delayingBlurEvent&&(e.hasFocus()?e.state.delayingBlurEvent=!1:Yr(e)),ve(o.wrapper.ownerDocument,"mouseup",c),ve(o.wrapper.ownerDocument,"mousemove",d),ve(o.scroller,"dragstart",f),ve(o.scroller,"drop",c),a||(Ce(t),i.addNew||Po(e.doc,n,null,null,i.extend),u&&!p||s&&9==l?setTimeout((function(){o.wrapper.ownerDocument.body.focus({preventScroll:!0}),o.input.focus()}),20):o.input.focus())})),d=r((function(e){a=a||Math.abs(t.clientX-e.clientX)+Math.abs(t.clientY-e.clientY)>=10}),"mouseMove"),f=r((function(){return a=!0}),"dragStart");u&&(o.scroller.draggable=!0),e.state.draggingText=c,c.copy=!i.moveOnDrag,me(o.wrapper.ownerDocument,"mouseup",c),me(o.wrapper.ownerDocument,"mousemove",d),me(o.scroller,"dragstart",f),me(o.scroller,"drop",c),e.state.delayingBlurEvent=!0,setTimeout((function(){return o.input.focus()}),20),o.scroller.dragDrop&&o.scroller.dragDrop()}function Ss(e,t,n){if("char"==n)return new ao(t,t);if("word"==n)return e.findWordAt(t);if("line"==n)return new ao(at(t.line,0),pt(e.doc,at(t.line+1,0)));var r=n(e,t);return new ao(r.from,r.to)}function xs(e,t,n,i){s&&Yr(e);var o=e.display,a=e.doc;Ce(t);var l,u,c=a.sel,d=c.ranges;if(i.addNew&&!i.extend?(u=a.sel.contains(n),l=u>-1?d[u]:new ao(n,n)):(l=a.sel.primary(),u=a.sel.primIndex),"rectangle"==i.unit)i.addNew||(l=new ao(n,n)),n=Fr(e,t,!0,!0),u=-1;else{var f=Ss(e,n,i.unit);l=i.extend?Fo(l,f.anchor,f.head,i.extend):f}i.addNew?-1==u?(u=d.length,qo(a,so(e,d.concat([l]),u),{scroll:!1,origin:"*mouse"})):d.length>1&&d[u].empty()&&"char"==i.unit&&!i.extend?(qo(a,so(e,d.slice(0,u).concat(d.slice(u+1)),0),{scroll:!1,origin:"*mouse"}),c=a.sel):Vo(a,u,l,G):(u=0,qo(a,new oo([l],0),G),c=a.sel);var p=n;function h(t){if(0!=st(p,t))if(p=t,"rectangle"==i.unit){for(var r=[],o=e.options.tabSize,s=V(Je(a,n.line).text,n.ch,o),d=V(Je(a,t.line).text,t.ch,o),f=Math.min(s,d),h=Math.max(s,d),m=Math.min(n.line,t.line),g=Math.min(e.lastLine(),Math.max(n.line,t.line));m<=g;m++){var v=Je(a,m).text,y=W(v,f,o);f==h?r.push(new ao(at(m,y),at(m,y))):v.length>y&&r.push(new ao(at(m,y),at(m,W(v,h,o))))}r.length||r.push(new ao(n,n)),qo(a,so(e,c.ranges.slice(0,u).concat(r),u),{origin:"*mouse",scroll:!1}),e.scrollIntoView(t)}else{var b,E=l,T=Ss(e,t,i.unit),w=E.anchor;st(T.anchor,w)>0?(b=T.head,w=dt(E.from(),T.anchor)):(b=T.anchor,w=ct(E.to(),T.head));var C=c.ranges.slice(0);C[u]=ks(e,new ao(pt(a,w),b)),qo(a,so(e,C,u),G)}}r(h,"extendTo");var m=o.wrapper.getBoundingClientRect(),g=0;function v(t){var n=++g,r=Fr(e,t,!0,"rectangle"==i.unit);if(r)if(0!=st(r,p)){e.curOp.focus=A(),h(r);var s=ni(o,a);(r.line>=s.to||r.linem.bottom?20:0;l&&setTimeout(Ai(e,(function(){g==n&&(o.scroller.scrollTop+=l,v(t))})),50)}}function y(t){e.state.selectingText=!1,g=1/0,t&&(Ce(t),o.input.focus()),ve(o.wrapper.ownerDocument,"mousemove",b),ve(o.wrapper.ownerDocument,"mouseup",E),a.history.lastSelOrigin=null}r(v,"extend"),r(y,"done");var b=Ai(e,(function(e){0!==e.buttons&&_e(e)?v(e):y(e)})),E=Ai(e,y);e.state.selectingText=E,me(o.wrapper.ownerDocument,"mousemove",b),me(o.wrapper.ownerDocument,"mouseup",E)}function ks(e,t){var n=t.anchor,r=t.head,i=Je(e.doc,n.line);if(0==st(n,r)&&n.sticky==r.sticky)return t;var o=pe(i);if(!o)return t;var a=de(o,n.ch,n.sticky),s=o[a];if(s.from!=n.ch&&s.to!=n.ch)return t;var l,u=a+(s.from==n.ch==(1!=s.level)?0:1);if(0==u||u==o.length)return t;if(r.line!=n.line)l=(r.line-n.line)*("ltr"==e.doc.direction?1:-1)>0;else{var c=de(o,r.ch,r.sticky),d=c-a||(r.ch-n.ch)*(1==s.level?-1:1);l=c==u-1||c==u?d<0:d>0}var f=o[u+(l?-1:0)],p=l==(1==f.level),h=p?f.from:f.to,m=p?"after":"before";return n.ch==h&&n.sticky==m?t:new ao(new at(n.line,h,m),r)}function Ns(e,t,n,r){var i,o;if(t.touches)i=t.touches[0].clientX,o=t.touches[0].clientY;else try{i=t.clientX,o=t.clientY}catch(e){return!1}if(i>=Math.floor(e.display.gutters.getBoundingClientRect().right))return!1;r&&Ce(t);var a=e.display,s=a.lineDiv.getBoundingClientRect();if(o>s.bottom||!Te(e,n))return xe(t);o-=s.top-a.viewOffset;for(var l=0;l=i)return ye(e,n,e,rt(e.doc,o),e.display.gutterSpecs[l].className,t),xe(t)}}function _s(e,t){return Ns(e,t,"gutterClick",!0)}function Os(e,t){Gn(e.display,t)||Is(e,t)||be(e,t,"contextmenu")||S||e.display.input.onContextMenu(t)}function Is(e,t){return!!Te(e,"gutterContextMenu")&&Ns(e,t,"gutterContextMenu",!1)}function Ds(e){e.display.wrapper.className=e.display.wrapper.className.replace(/\s*cm-s-\S+/g,"")+e.options.theme.replace(/(^|\s)\s*/g," cm-s-"),pr(e)}vs.prototype.compare=function(e,t,n){return this.time+gs>e&&0==st(t,this.pos)&&n==this.button},r(ys,"clickRepeat"),r(bs,"onMouseDown"),r(Es,"handleMappedButton"),r(Ts,"configureMouse"),r(ws,"leftButtonDown"),r(Cs,"leftButtonStartDrag"),r(Ss,"rangeForUnit"),r(xs,"leftButtonSelect"),r(ks,"bidiSimplify"),r(Ns,"gutterEvent"),r(_s,"clickInGutter"),r(Os,"onContextMenu"),r(Is,"contextMenuInGutter"),r(Ds,"themeChanged");var Ls={toString:function(){return"CodeMirror.Init"}},As={},Ms={};function Rs(e){var t=e.optionHandlers;function n(n,r,i,o){e.defaults[n]=r,i&&(t[n]=o?function(e,t,n){n!=Ls&&i(e,t,n)}:i)}r(n,"option"),e.defineOption=n,e.Init=Ls,n("value","",(function(e,t){return e.setValue(t)}),!0),n("mode",null,(function(e,t){e.doc.modeOption=t,mo(e)}),!0),n("indentUnit",2,mo,!0),n("indentWithTabs",!1),n("smartIndent",!0),n("tabSize",4,(function(e){go(e),pr(e),jr(e)}),!0),n("lineSeparator",null,(function(e,t){if(e.doc.lineSep=t,t){var n=[],r=e.doc.first;e.doc.iter((function(e){for(var i=0;;){var o=e.text.indexOf(t,i);if(-1==o)break;i=o+t.length,n.push(at(r,o))}r++}));for(var i=n.length-1;i>=0;i--)oa(e.doc,t,n[i],at(n[i].line,n[i].ch+t.length))}})),n("specialChars",/[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b\u200e\u200f\u2028\u2029\ufeff\ufff9-\ufffc]/g,(function(e,t,n){e.state.specialChars=new RegExp(t.source+(t.test("\t")?"":"|\t"),"g"),n!=Ls&&e.refresh()})),n("specialCharPlaceholder",vn,(function(e){return e.refresh()}),!0),n("electricChars",!0),n("inputStyle",y?"contenteditable":"textarea",(function(){throw new Error("inputStyle can not (yet) be changed in a running editor")}),!0),n("spellcheck",!1,(function(e,t){return e.getInputField().spellcheck=t}),!0),n("autocorrect",!1,(function(e,t){return e.getInputField().autocorrect=t}),!0),n("autocapitalize",!1,(function(e,t){return e.getInputField().autocapitalize=t}),!0),n("rtlMoveVisually",!T),n("wholeLineUpdateBefore",!0),n("theme","default",(function(e){Ds(e),Ji(e)}),!0),n("keyMap","default",(function(e,t,n){var r=za(t),i=n!=Ls&&za(n);i&&i.detach&&i.detach(e,r),r.attach&&r.attach(e,i||null)})),n("extraKeys",null),n("configureMouse",null),n("lineWrapping",!1,Ps,!0),n("gutters",[],(function(e,t){e.display.gutterSpecs=Xi(t,e.options.lineNumbers),Ji(e)}),!0),n("fixedGutter",!0,(function(e,t){e.display.gutters.style.left=t?Ar(e.display)+"px":"0",e.refresh()}),!0),n("coverGutterNextToScrollbar",!1,(function(e){return bi(e)}),!0),n("scrollbarStyle","native",(function(e){wi(e),bi(e),e.display.scrollbars.setScrollTop(e.doc.scrollTop),e.display.scrollbars.setScrollLeft(e.doc.scrollLeft)}),!0),n("lineNumbers",!1,(function(e,t){e.display.gutterSpecs=Xi(e.options.gutters,t),Ji(e)}),!0),n("firstLineNumber",1,Ji,!0),n("lineNumberFormatter",(function(e){return e}),Ji,!0),n("showCursorWhenSelecting",!1,Hr,!0),n("resetSelectionOnContextMenu",!0),n("lineWiseCopyCut",!0),n("pasteLinesPerSelection",!0),n("selectionsMayTouch",!1),n("readOnly",!1,(function(e,t){"nocursor"==t&&(Zr(e),e.display.input.blur()),e.display.input.readOnlyChanged(t)})),n("screenReaderLabel",null,(function(e,t){t=""===t?null:t,e.display.input.screenReaderLabelChanged(t)})),n("disableInput",!1,(function(e,t){t||e.display.input.reset()}),!0),n("dragDrop",!0,Fs),n("allowDropFileTypes",null),n("cursorBlinkRate",530),n("cursorScrollMargin",0),n("cursorHeight",1,Hr,!0),n("singleCursorHeightPerLine",!0,Hr,!0),n("workTime",100),n("workDelay",100),n("flattenSpans",!0,go,!0),n("addModeClass",!1,go,!0),n("pollInterval",100),n("undoDepth",200,(function(e,t){return e.doc.history.undoDepth=t})),n("historyEventDelay",1250),n("viewportMargin",10,(function(e){return e.refresh()}),!0),n("maxHighlightLength",1e4,go,!0),n("moveInputWithCursor",!0,(function(e,t){t||e.display.input.resetPosition()})),n("tabindex",null,(function(e,t){return e.display.input.getField().tabIndex=t||""})),n("autofocus",null),n("direction","ltr",(function(e,t){return e.doc.setDirection(t)}),!0),n("phrases",null)}function Fs(e,t,n){if(!t!=!(n&&n!=Ls)){var r=e.display.dragFunctions,i=t?me:ve;i(e.display.scroller,"dragstart",r.start),i(e.display.scroller,"dragenter",r.enter),i(e.display.scroller,"dragover",r.over),i(e.display.scroller,"dragleave",r.leave),i(e.display.scroller,"drop",r.drop)}}function Ps(e){e.options.lineWrapping?(M(e.display.wrapper,"CodeMirror-wrap"),e.display.sizer.style.minWidth="",e.display.sizerWidth=null):(N(e.display.wrapper,"CodeMirror-wrap"),un(e)),Rr(e),jr(e),pr(e),setTimeout((function(){return bi(e)}),100)}function js(e,t){var n=this;if(!(this instanceof js))return new js(e,t);this.options=t=t?j(t):{},j(As,t,!1);var r=t.value;"string"==typeof r?r=new Sa(r,t.mode,null,t.lineSeparator,t.direction):t.mode&&(r.modeOption=t.mode),this.doc=r;var i=new js.inputStyles[t.inputStyle](this),o=this.display=new Zi(e,r,i,t);for(var a in o.wrapper.CodeMirror=this,Ds(this),t.lineWrapping&&(this.display.wrapper.className+=" CodeMirror-wrap"),wi(this),this.state={keyMaps:[],overlays:[],modeGen:0,overwrite:!1,delayingBlurEvent:!1,focused:!1,suppressEdits:!1,pasteIncoming:-1,cutIncoming:-1,selectingText:!1,draggingText:!1,highlight:new U,keySeq:null,specialChars:null},t.autofocus&&!y&&o.input.focus(),s&&l<11&&setTimeout((function(){return n.display.input.reset(!0)}),20),Vs(this),La(),Si(this),this.curOp.forceUpdate=!0,Eo(this,r),t.autofocus&&!y||this.hasFocus()?setTimeout((function(){n.hasFocus()&&!n.state.focused&&Jr(n)}),20):Zr(this),Ms)Ms.hasOwnProperty(a)&&Ms[a](this,t[a],Ls);Qi(this),t.finishInit&&t.finishInit(this);for(var c=0;c400}r(o,"finishTouch"),r(a,"isMouseLikeTouchEvent"),r(u,"farAway"),me(t.scroller,"touchstart",(function(r){if(!be(e,r)&&!a(r)&&!_s(e,r)){t.input.ensurePolled(),clearTimeout(n);var o=+new Date;t.activeTouch={start:o,moved:!1,prev:o-i.end<=300?i:null},1==r.touches.length&&(t.activeTouch.left=r.touches[0].pageX,t.activeTouch.top=r.touches[0].pageY)}})),me(t.scroller,"touchmove",(function(){t.activeTouch&&(t.activeTouch.moved=!0)})),me(t.scroller,"touchend",(function(n){var r=t.activeTouch;if(r&&!Gn(t,n)&&null!=r.left&&!r.moved&&new Date-r.start<300){var i,a=e.coordsChar(t.activeTouch,"page");i=!r.prev||u(r,r.prev)?new ao(a,a):!r.prev.prev||u(r,r.prev.prev)?e.findWordAt(a):new ao(at(a.line,0),pt(e.doc,at(a.line+1,0))),e.setSelection(i.anchor,i.head),e.focus(),Ce(n)}o()})),me(t.scroller,"touchcancel",o),me(t.scroller,"scroll",(function(){t.scroller.clientHeight&&(pi(e,t.scroller.scrollTop),mi(e,t.scroller.scrollLeft,!0),ye(e,"scroll",e))})),me(t.scroller,"mousewheel",(function(t){return io(e,t)})),me(t.scroller,"DOMMouseScroll",(function(t){return io(e,t)})),me(t.wrapper,"scroll",(function(){return t.wrapper.scrollTop=t.wrapper.scrollLeft=0})),t.dragFunctions={enter:function(t){be(e,t)||ke(t)},over:function(t){be(e,t)||(_a(e,t),ke(t))},start:function(t){return Na(e,t)},drop:Ai(e,ka),leave:function(t){be(e,t)||Oa(e)}};var c=t.input.getField();me(c,"keyup",(function(t){return fs.call(e,t)})),me(c,"keydown",Ai(e,cs)),me(c,"keypress",Ai(e,ps)),me(c,"focus",(function(t){return Jr(e,t)})),me(c,"blur",(function(t){return Zr(e,t)}))}r(Rs,"defineOptions"),r(Fs,"dragDropChanged"),r(Ps,"wrappingChanged"),r(js,"CodeMirror"),js.defaults=As,js.optionHandlers=Ms,r(Vs,"registerEventHandlers");var Us=[];function Bs(e,t,n,r){var i,o=e.doc;null==n&&(n="add"),"smart"==n&&(o.mode.indent?i=Et(e,t).state:n="prev");var a=e.options.tabSize,s=Je(o,t),l=V(s.text,null,a);s.stateAfter&&(s.stateAfter=null);var u,c=s.text.match(/^\s*/)[0];if(r||/\S/.test(s.text)){if("smart"==n&&((u=o.mode.indent(i,s.text.slice(c.length),s.text))==q||u>150)){if(!r)return;n="prev"}}else u=0,n="not";"prev"==n?u=t>o.first?V(Je(o,t-1).text,null,a):0:"add"==n?u=l+e.options.indentUnit:"subtract"==n?u=l-e.options.indentUnit:"number"==typeof n&&(u=l+n),u=Math.max(0,u);var d="",f=0;if(e.options.indentWithTabs)for(var p=Math.floor(u/a);p;--p)f+=a,d+="\t";if(fa,l=Re(t),u=null;if(s&&r.ranges.length>1)if($s&&$s.text.join("\n")==t){if(r.ranges.length%$s.text.length==0){u=[];for(var c=0;c<$s.text.length;c++)u.push(o.splitLines($s.text[c]))}}else l.length==r.ranges.length&&e.options.pasteLinesPerSelection&&(u=Y(l,(function(e){return[e]})));for(var d=e.curOp.updateInput,f=r.ranges.length-1;f>=0;f--){var p=r.ranges[f],h=p.from(),m=p.to();p.empty()&&(n&&n>0?h=at(h.line,h.ch-n):e.state.overwrite&&!s?m=at(m.line,Math.min(Je(o,m.line).text.length,m.ch+X(l).length)):s&&$s&&$s.lineWise&&$s.text.join("\n")==l.join("\n")&&(h=m=at(h.line,0)));var g={from:h,to:m,text:u?u[f%u.length]:l,origin:i||(s?"paste":e.state.cutIncoming>a?"cut":"+input")};Zo(e.doc,g),In(e,"inputRead",e,g)}t&&!s&&zs(e,t),li(e),e.curOp.updateInput<2&&(e.curOp.updateInput=d),e.curOp.typing=!0,e.state.pasteIncoming=e.state.cutIncoming=-1}function Gs(e,t){var n=e.clipboardData&&e.clipboardData.getData("Text");if(n)return e.preventDefault(),t.isReadOnly()||t.options.disableInput||Li(t,(function(){return Hs(t,n,0,null,"paste")})),!0}function zs(e,t){if(e.options.electricChars&&e.options.smartIndent)for(var n=e.doc.sel,r=n.ranges.length-1;r>=0;r--){var i=n.ranges[r];if(!(i.head.ch>100||r&&n.ranges[r-1].head.line==i.head.line)){var o=e.getModeAt(i.head),a=!1;if(o.electricChars){for(var s=0;s-1){a=Bs(e,i.head.line,"smart");break}}else o.electricInput&&o.electricInput.test(Je(e.doc,i.head.line).text.slice(0,i.head.ch))&&(a=Bs(e,i.head.line,"smart"));a&&In(e,"electricInput",e,i.head.line)}}}function Ws(e){for(var t=[],n=[],r=0;rn&&(Bs(this,i.head.line,e,!0),n=i.head.line,r==this.doc.sel.primIndex&&li(this));else{var o=i.from(),a=i.to(),s=Math.max(n,o.line);n=Math.min(this.lastLine(),a.line-(a.ch?0:1))+1;for(var l=s;l0&&Vo(this.doc,r,new ao(o,u[r].to()),H)}}})),getTokenAt:function(e,t){return xt(this,e,t)},getLineTokens:function(e,t){return xt(this,at(e),t,!0)},getTokenTypeAt:function(e){e=pt(this.doc,e);var t,n=bt(this,Je(this.doc,e.line)),r=0,i=(n.length-1)/2,o=e.ch;if(0==o)t=n[2];else for(;;){var a=r+i>>1;if((a?n[2*a-1]:0)>=o)i=a;else{if(!(n[2*a+1]o&&(e=o,i=!0),r=Je(this.doc,e)}else r=e;return vr(this,r,{top:0,left:0},t||"page",n||i).top+(i?this.doc.height-sn(r):0)},defaultTextHeight:function(){return Ir(this.display)},defaultCharWidth:function(){return Dr(this.display)},getViewport:function(){return{from:this.display.viewFrom,to:this.display.viewTo}},addWidget:function(e,t,n,r,i){var o=this.display,a=(e=Er(this,pt(this.doc,e))).bottom,s=e.left;if(t.style.position="absolute",t.setAttribute("cm-ignore-events","true"),this.display.input.setUneditable(t),o.sizer.appendChild(t),"over"==r)a=e.top;else if("above"==r||"near"==r){var l=Math.max(o.wrapper.clientHeight,this.doc.height),u=Math.max(o.sizer.clientWidth,o.lineSpace.clientWidth);("above"==r||e.bottom+t.offsetHeight>l)&&e.top>t.offsetHeight?a=e.top-t.offsetHeight:e.bottom+t.offsetHeight<=l&&(a=e.bottom),s+t.offsetWidth>u&&(s=u-t.offsetWidth)}t.style.top=a+"px",t.style.left=t.style.right="","right"==i?(s=o.sizer.clientWidth-t.offsetWidth,t.style.right="0px"):("left"==i?s=0:"middle"==i&&(s=(o.sizer.clientWidth-t.offsetWidth)/2),t.style.left=s+"px"),n&&oi(this,{left:s,top:a,right:s+t.offsetWidth,bottom:a+t.offsetHeight})},triggerOnKeyDown:Mi(cs),triggerOnKeyPress:Mi(ps),triggerOnKeyUp:fs,triggerOnMouseDown:Mi(bs),execCommand:function(e){if(Ja.hasOwnProperty(e))return Ja[e].call(null,this)},triggerElectric:Mi((function(e){zs(this,e)})),findPosH:function(e,t,n,r){var i=1;t<0&&(i=-1,t=-t);for(var o=pt(this.doc,e),a=0;a0&&a(t.charAt(n-1));)--n;for(;r.5||this.options.lineWrapping)&&Rr(this),ye(this,"refresh",this)})),swapDoc:Mi((function(e){var t=this.doc;return t.cm=null,this.state.selectingText&&this.state.selectingText(),Eo(this,e),pr(this),this.display.input.reset(),ui(this,e.scrollLeft,e.scrollTop),this.curOp.forceScroll=!0,In(this,"swapDoc",this,t),t})),phrase:function(e){var t=this.options.phrases;return t&&Object.prototype.hasOwnProperty.call(t,e)?t[e]:e},getInputField:function(){return this.display.input.getField()},getWrapperElement:function(){return this.display.wrapper},getScrollerElement:function(){return this.display.scroller},getGutterElement:function(){return this.display.gutters}},we(e),e.registerHelper=function(t,r,i){n.hasOwnProperty(t)||(n[t]=e[t]={_global:[]}),n[t][r]=i},e.registerGlobalHelper=function(t,r,i,o){e.registerHelper(t,r,o),n[t]._global.push({pred:i,val:o})}}function Ys(e,t,n,i,o){var a=t,s=n,l=Je(e,t.line),u=o&&"rtl"==e.direction?-n:n;function c(){var n=t.line+u;return!(n=e.first+e.size)&&(t=new at(n,t.ch,t.sticky),l=Je(e,n))}function d(r){var a;if("codepoint"==i){var s=l.text.charCodeAt(t.ch+(n>0?0:-1));if(isNaN(s))a=null;else{var d=n>0?s>=55296&&s<56320:s>=56320&&s<57343;a=new at(t.line,Math.max(0,Math.min(l.text.length,t.ch+n*(d?2:1))),-n)}}else a=o?Ya(e.cm,l,t,n):Qa(l,t,n);if(null==a){if(r||!c())return!1;t=Xa(o,e.cm,l,t.line,u)}else t=a;return!0}if(r(c,"findNextLine"),r(d,"moveOnce"),"char"==i||"codepoint"==i)d();else if("column"==i)d(!0);else if("word"==i||"group"==i)for(var f=null,p="group"==i,h=e.cm&&e.cm.getHelper(t,"wordChars"),m=!0;!(n<0)||d(!m);m=!1){var g=l.text.charAt(t.ch)||"\n",v=re(g,h)?"w":p&&"\n"==g?"n":!p||/\s/.test(g)?null:"p";if(!p||m||v||(v="s"),f&&f!=v){n<0&&(n=1,d(),t.sticky="after");break}if(v&&(f=v),n>0&&!d(!m))break}var y=Qo(e,t,a,s,!0);return lt(a,y)&&(y.hitSide=!0),y}function Js(e,t,n,r){var i,o,a=e.doc,s=t.left;if("page"==r){var l=Math.min(e.display.wrapper.clientHeight,window.innerHeight||document.documentElement.clientHeight),u=Math.max(l-.5*Ir(e.display),3);i=(n>0?t.bottom:t.top)+n*u}else"line"==r&&(i=n>0?t.bottom+3:t.top-3);for(;(o=Cr(e,s,i)).outside;){if(n<0?i<=0:i>=a.height){o.hitSide=!0;break}i+=5*n}return o}r(qs,"setLastCopied"),r(Hs,"applyTextInput"),r(Gs,"handlePaste"),r(zs,"triggerElectric"),r(Ws,"copyableRanges"),r(Ks,"disableBrowserMagic"),r(Qs,"hiddenTextarea"),r(Xs,"addEditorMethods"),r(Ys,"findPosH"),r(Js,"findPosV");var Zs=r((function(e){this.cm=e,this.lastAnchorNode=this.lastAnchorOffset=this.lastFocusNode=this.lastFocusOffset=null,this.polling=new U,this.composing=null,this.gracePeriod=!1,this.readDOMTimeout=null}),"ContentEditableInput");function el(e,t){var n=nr(e,t.line);if(!n||n.hidden)return null;var r=Je(e.doc,t.line),i=Zn(n,r,t.line),o=pe(r,e.doc.direction),a="left";o&&(a=de(o,t.ch)%2?"right":"left");var s=sr(i.map,t.ch,a);return s.offset="right"==s.collapse?s.end:s.start,s}function tl(e){for(var t=e;t;t=t.parentNode)if(/CodeMirror-gutter-wrapper/.test(t.className))return!0;return!1}function nl(e,t){return t&&(e.bad=!0),e}function rl(e,t,n,i,o){var a="",s=!1,l=e.doc.lineSeparator(),u=!1;function c(e){return function(t){return t.id==e}}function d(){s&&(a+=l,u&&(a+=l),s=u=!1)}function f(e){e&&(d(),a+=e)}function p(t){if(1==t.nodeType){var n=t.getAttribute("cm-text");if(n)return void f(n);var r,a=t.getAttribute("cm-marker");if(a){var h=e.findMarks(at(i,0),at(o+1,0),c(+a));return void(h.length&&(r=h[0].find(0))&&f(Ze(e.doc,r.from,r.to).join(l)))}if("false"==t.getAttribute("contenteditable"))return;var m=/^(pre|div|p|li|table|br)$/i.test(t.nodeName);if(!/^br$/i.test(t.nodeName)&&0==t.textContent.length)return;m&&d();for(var g=0;g=t.display.viewTo||o.line=t.display.viewFrom&&el(t,i)||{node:l[0].measure.map[2],offset:0},c=o.liner.firstLine()&&(a=at(a.line-1,Je(r.doc,a.line-1).length)),s.ch==Je(r.doc,s.line).text.length&&s.linei.viewTo-1)return!1;a.line==i.viewFrom||0==(e=Pr(r,a.line))?(t=nt(i.view[0].line),n=i.view[0].node):(t=nt(i.view[e].line),n=i.view[e-1].node.nextSibling);var l,u,c=Pr(r,s.line);if(c==i.view.length-1?(l=i.viewTo-1,u=i.lineDiv.lastChild):(l=nt(i.view[c+1].line)-1,u=i.view[c+1].node.previousSibling),!n)return!1;for(var d=r.doc.splitLines(rl(r,n,u,t,l)),f=Ze(r.doc,at(t,0),at(l,Je(r.doc,l).text.length));d.length>1&&f.length>1;)if(X(d)==X(f))d.pop(),f.pop(),l--;else{if(d[0]!=f[0])break;d.shift(),f.shift(),t++}for(var p=0,h=0,m=d[0],g=f[0],v=Math.min(m.length,g.length);pa.ch&&y.charCodeAt(y.length-h-1)==b.charCodeAt(b.length-h-1);)p--,h++;d[d.length-1]=y.slice(0,y.length-h).replace(/^\u200b+/,""),d[0]=d[0].slice(p).replace(/\u200b+$/,"");var T=at(t,p),w=at(l,f.length?X(f).length-h:0);return d.length>1||d[0]||st(T,w)?(oa(r.doc,d,T,w,"+input"),!0):void 0},Zs.prototype.ensurePolled=function(){this.forceCompositionEnd()},Zs.prototype.reset=function(){this.forceCompositionEnd()},Zs.prototype.forceCompositionEnd=function(){this.composing&&(clearTimeout(this.readDOMTimeout),this.composing=null,this.updateFromDOM(),this.div.blur(),this.div.focus())},Zs.prototype.readFromDOMSoon=function(){var e=this;null==this.readDOMTimeout&&(this.readDOMTimeout=setTimeout((function(){if(e.readDOMTimeout=null,e.composing){if(!e.composing.done)return;e.composing=null}e.updateFromDOM()}),80))},Zs.prototype.updateFromDOM=function(){var e=this;!this.cm.isReadOnly()&&this.pollContent()||Li(this.cm,(function(){return jr(e.cm)}))},Zs.prototype.setUneditable=function(e){e.contentEditable="false"},Zs.prototype.onKeyPress=function(e){0==e.charCode||this.composing||(e.preventDefault(),this.cm.isReadOnly()||Ai(this.cm,Hs)(this.cm,String.fromCharCode(null==e.charCode?e.keyCode:e.charCode),0))},Zs.prototype.readOnlyChanged=function(e){this.div.contentEditable=String("nocursor"!=e)},Zs.prototype.onContextMenu=function(){},Zs.prototype.resetPosition=function(){},Zs.prototype.needsContentAttribute=!0,r(el,"posToDOM"),r(tl,"isInGutter"),r(nl,"badPos"),r(rl,"domTextBetween"),r(il,"domToPos"),r(ol,"locateNodeInLineView");var al=r((function(e){this.cm=e,this.prevInput="",this.pollingFast=!1,this.polling=new U,this.hasSelection=!1,this.composing=null}),"TextareaInput");function sl(e,t){if((t=t?j(t):{}).value=e.value,!t.tabindex&&e.tabIndex&&(t.tabindex=e.tabIndex),!t.placeholder&&e.placeholder&&(t.placeholder=e.placeholder),null==t.autofocus){var n=A();t.autofocus=n==e||null!=e.getAttribute("autofocus")&&n==document.body}function i(){e.value=l.getValue()}var o;if(r(i,"save"),e.form&&(me(e.form,"submit",i),!t.leaveSubmitMethodAlone)){var a=e.form;o=a.submit;try{var s=a.submit=function(){i(),a.submit=o,a.submit(),a.submit=s}}catch(e){}}t.finishInit=function(n){n.save=i,n.getTextArea=function(){return e},n.toTextArea=function(){n.toTextArea=isNaN,i(),e.parentNode.removeChild(n.getWrapperElement()),e.style.display="",e.form&&(ve(e.form,"submit",i),t.leaveSubmitMethodAlone||"function"!=typeof e.form.submit||(e.form.submit=o))}},e.style.display="none";var l=js((function(t){return e.parentNode.insertBefore(t,e.nextSibling)}),t);return l}function ll(e){e.off=ve,e.on=me,e.wheelEventPixels=ro,e.Doc=Sa,e.splitLines=Re,e.countColumn=V,e.findColumn=W,e.isWordChar=ne,e.Pass=q,e.signal=ye,e.Line=cn,e.changeEnd=uo,e.scrollbarModel=Ti,e.Pos=at,e.cmpPos=st,e.modes=Ue,e.mimeModes=Be,e.resolveMode=He,e.getMode=Ge,e.modeExtensions=ze,e.extendMode=We,e.copyState=Ke,e.startState=Xe,e.innerMode=Qe,e.commands=Ja,e.keyMap=Va,e.keyName=Ga,e.isModifierKey=qa,e.lookupKey=$a,e.normalizeKeyMap=Ba,e.StringStream=Ye,e.SharedTextMarker=ya,e.TextMarker=ga,e.LineWidget=fa,e.e_preventDefault=Ce,e.e_stopPropagation=Se,e.e_stop=ke,e.addClass=M,e.contains=L,e.rmClass=N,e.keyNames=Ra}al.prototype.init=function(e){var t=this,n=this,i=this.cm;this.createField(e);var o=this.textarea;function a(e){if(!be(i,e)){if(i.somethingSelected())qs({lineWise:!1,text:i.getSelections()});else{if(!i.options.lineWiseCopyCut)return;var t=Ws(i);qs({lineWise:!0,text:t.text}),"cut"==e.type?i.setSelections(t.ranges,null,H):(n.prevInput="",o.value=t.text.join("\n"),F(o))}"cut"==e.type&&(i.state.cutIncoming=+new Date)}}e.wrapper.insertBefore(this.wrapper,e.wrapper.firstChild),g&&(o.style.width="0px"),me(o,"input",(function(){s&&l>=9&&t.hasSelection&&(t.hasSelection=null),n.poll()})),me(o,"paste",(function(e){be(i,e)||Gs(e,i)||(i.state.pasteIncoming=+new Date,n.fastPoll())})),r(a,"prepareCopyCut"),me(o,"cut",a),me(o,"copy",a),me(e.scroller,"paste",(function(t){if(!Gn(e,t)&&!be(i,t)){if(!o.dispatchEvent)return i.state.pasteIncoming=+new Date,void n.focus();var r=new Event("paste");r.clipboardData=t.clipboardData,o.dispatchEvent(r)}})),me(e.lineSpace,"selectstart",(function(t){Gn(e,t)||Ce(t)})),me(o,"compositionstart",(function(){var e=i.getCursor("from");n.composing&&n.composing.range.clear(),n.composing={start:e,range:i.markText(e,i.getCursor("to"),{className:"CodeMirror-composing"})}})),me(o,"compositionend",(function(){n.composing&&(n.poll(),n.composing.range.clear(),n.composing=null)}))},al.prototype.createField=function(e){this.wrapper=Qs(),this.textarea=this.wrapper.firstChild},al.prototype.screenReaderLabelChanged=function(e){e?this.textarea.setAttribute("aria-label",e):this.textarea.removeAttribute("aria-label")},al.prototype.prepareSelection=function(){var e=this.cm,t=e.display,n=e.doc,r=Gr(e);if(e.options.moveInputWithCursor){var i=Er(e,n.sel.primary().head,"div"),o=t.wrapper.getBoundingClientRect(),a=t.lineDiv.getBoundingClientRect();r.teTop=Math.max(0,Math.min(t.wrapper.clientHeight-10,i.top+a.top-o.top)),r.teLeft=Math.max(0,Math.min(t.wrapper.clientWidth-10,i.left+a.left-o.left))}return r},al.prototype.showSelection=function(e){var t=this.cm.display;O(t.cursorDiv,e.cursors),O(t.selectionDiv,e.selection),null!=e.teTop&&(this.wrapper.style.top=e.teTop+"px",this.wrapper.style.left=e.teLeft+"px")},al.prototype.reset=function(e){if(!this.contextMenuPending&&!this.composing){var t=this.cm;if(t.somethingSelected()){this.prevInput="";var n=t.getSelection();this.textarea.value=n,t.state.focused&&F(this.textarea),s&&l>=9&&(this.hasSelection=n)}else e||(this.prevInput=this.textarea.value="",s&&l>=9&&(this.hasSelection=null))}},al.prototype.getField=function(){return this.textarea},al.prototype.supportsTouch=function(){return!1},al.prototype.focus=function(){if("nocursor"!=this.cm.options.readOnly&&(!y||A()!=this.textarea))try{this.textarea.focus()}catch(e){}},al.prototype.blur=function(){this.textarea.blur()},al.prototype.resetPosition=function(){this.wrapper.style.top=this.wrapper.style.left=0},al.prototype.receivedFocus=function(){this.slowPoll()},al.prototype.slowPoll=function(){var e=this;this.pollingFast||this.polling.set(this.cm.options.pollInterval,(function(){e.poll(),e.cm.state.focused&&e.slowPoll()}))},al.prototype.fastPoll=function(){var e=!1,t=this;function n(){t.poll()||e?(t.pollingFast=!1,t.slowPoll()):(e=!0,t.polling.set(60,n))}t.pollingFast=!0,r(n,"p"),t.polling.set(20,n)},al.prototype.poll=function(){var e=this,t=this.cm,n=this.textarea,r=this.prevInput;if(this.contextMenuPending||!t.state.focused||Fe(n)&&!r&&!this.composing||t.isReadOnly()||t.options.disableInput||t.state.keySeq)return!1;var i=n.value;if(i==r&&!t.somethingSelected())return!1;if(s&&l>=9&&this.hasSelection===i||b&&/[\uf700-\uf7ff]/.test(i))return t.display.input.reset(),!1;if(t.doc.sel==t.display.selForContextMenu){var o=i.charCodeAt(0);if(8203!=o||r||(r="​"),8666==o)return this.reset(),this.cm.execCommand("undo")}for(var a=0,u=Math.min(r.length,i.length);a1e3||i.indexOf("\n")>-1?n.value=e.prevInput="":e.prevInput=i,e.composing&&(e.composing.range.clear(),e.composing.range=t.markText(e.composing.start,t.getCursor("to"),{className:"CodeMirror-composing"}))})),!0},al.prototype.ensurePolled=function(){this.pollingFast&&this.poll()&&(this.pollingFast=!1)},al.prototype.onKeyPress=function(){s&&l>=9&&(this.hasSelection=null),this.fastPoll()},al.prototype.onContextMenu=function(e){var t=this,n=t.cm,i=n.display,o=t.textarea;t.contextMenuPending&&t.contextMenuPending();var a=Fr(n,e),c=i.scroller.scrollTop;if(a&&!f){n.options.resetSelectionOnContextMenu&&-1==n.doc.sel.contains(a)&&Ai(n,qo)(n.doc,lo(a),H);var d,p=o.style.cssText,h=t.wrapper.style.cssText,m=t.wrapper.offsetParent.getBoundingClientRect();if(t.wrapper.style.cssText="position: static",o.style.cssText="position: absolute; width: 30px; height: 30px;\n top: "+(e.clientY-m.top-5)+"px; left: "+(e.clientX-m.left-5)+"px;\n z-index: 1000; background: "+(s?"rgba(255, 255, 255, .05)":"transparent")+";\n outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);",u&&(d=window.scrollY),i.input.focus(),u&&window.scrollTo(null,d),i.input.reset(),n.somethingSelected()||(o.value=t.prevInput=" "),t.contextMenuPending=y,i.selForContextMenu=n.doc.sel,clearTimeout(i.detectingSelectAll),r(v,"prepareSelectAllHack"),r(y,"rehide"),s&&l>=9&&v(),S){ke(e);var g=r((function(){ve(window,"mouseup",g),setTimeout(y,20)}),"mouseup");me(window,"mouseup",g)}else setTimeout(y,50)}function v(){if(null!=o.selectionStart){var e=n.somethingSelected(),r="​"+(e?o.value:"");o.value="⇚",o.value=r,t.prevInput=e?"":"​",o.selectionStart=1,o.selectionEnd=r.length,i.selForContextMenu=n.doc.sel}}function y(){if(t.contextMenuPending==y&&(t.contextMenuPending=!1,t.wrapper.style.cssText=h,o.style.cssText=p,s&&l<9&&i.scrollbars.setScrollTop(i.scroller.scrollTop=c),null!=o.selectionStart)){(!s||s&&l<9)&&v();var e=0,a=r((function(){i.selForContextMenu==n.doc.sel&&0==o.selectionStart&&o.selectionEnd>0&&"​"==t.prevInput?Ai(n,Yo)(n):e++<10?i.detectingSelectAll=setTimeout(a,500):(i.selForContextMenu=null,i.input.reset())}),"poll");i.detectingSelectAll=setTimeout(a,200)}}},al.prototype.readOnlyChanged=function(e){e||this.reset(),this.textarea.disabled="nocursor"==e,this.textarea.readOnly=!!e},al.prototype.setUneditable=function(){},al.prototype.needsContentAttribute=!1,r(sl,"fromTextArea"),r(ll,"addLegacyProps"),Rs(js),Xs(js);var ul="iter insert remove copy getEditor constructor".split(" ");for(var cl in Sa.prototype)Sa.prototype.hasOwnProperty(cl)&&B(ul,cl)<0&&(js.prototype[cl]=function(e){return function(){return e.apply(this.doc,arguments)}}(Sa.prototype[cl]));return we(Sa),js.inputStyles={textarea:al,contenteditable:Zs},js.defineMode=function(e){js.defaults.mode||"null"==e||(js.defaults.mode=e),$e.apply(this,arguments)},js.defineMIME=qe,js.defineMode("null",(function(){return{token:function(e){return e.skipToEnd()}}})),js.defineMIME("text/plain","null"),js.defineExtension=function(e,t){js.prototype[e]=t},js.defineDocExtension=function(e,t){Sa.prototype[e]=t},js.fromTextArea=sl,ll(js),js.version="5.65.3",js}()}(o);var a=o.exports;e.C=a;var s=i({__proto__:null,default:a},[o.exports]);e.c=s},void 0===(o=r.apply(t,i))||(e.exports=o)},6754:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[t,n(535)],void 0===(o="function"==typeof(r=function(e,t){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.c=void 0;var n=Object.defineProperty,r=(e,t)=>n(e,"name",{value:t,configurable:!0});function i(e,t){return t.forEach((function(t){t&&"string"!=typeof t&&!Array.isArray(t)&&Object.keys(t).forEach((function(n){if("default"!==n&&!(n in e)){var r=Object.getOwnPropertyDescriptor(t,n);Object.defineProperty(e,n,r.get?r:{enumerable:!0,get:function(){return t[n]}})}}))})),Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}r(i,"_mergeNamespaces");var o={exports:{}};!function(e){var t={},n=/[^\s\u00a0]/,i=e.Pos,o=e.cmpPos;function a(e){var t=e.search(n);return-1==t?0:t}function s(e,t,n){return/\bstring\b/.test(e.getTokenTypeAt(i(t.line,0)))&&!/^[\'\"\`]/.test(n)}function l(e,t){var n=e.getMode();return!1!==n.useInnerComments&&n.innerMode?e.getModeAt(t):n}r(a,"firstNonWS"),e.commands.toggleComment=function(e){e.toggleComment()},e.defineExtension("toggleComment",(function(e){e||(e=t);for(var n=this,r=1/0,o=this.listSelections(),a=null,s=o.length-1;s>=0;s--){var l=o[s].from(),u=o[s].to();l.line>=r||(u.line>=r&&(u=i(r,0)),r=l.line,null==a?n.uncomment(l,u,e)?a="un":(n.lineComment(l,u,e),a="line"):"un"==a?n.uncomment(l,u,e):n.lineComment(l,u,e))}})),r(s,"probablyInsideString"),r(l,"getMode"),e.defineExtension("lineComment",(function(e,r,o){o||(o=t);var u=this,c=l(u,e),d=u.getLine(e.line);if(null!=d&&!s(u,e,d)){var f=o.lineComment||c.lineComment;if(f){var p=Math.min(0!=r.ch||r.line==e.line?r.line+1:r.line,u.lastLine()+1),h=null==o.padding?" ":o.padding,m=o.commentBlankLines||e.line==r.line;u.operation((function(){if(o.indent){for(var t=null,r=e.line;rs.length)&&(t=s)}for(r=e.line;rf||s.operation((function(){if(0!=a.fullLines){var t=n.test(s.getLine(f));s.replaceRange(p+d,i(f)),s.replaceRange(c+p,i(e.line,0));var l=a.blockCommentLead||u.blockCommentLead;if(null!=l)for(var h=e.line+1;h<=f;++h)(h!=f||t)&&s.replaceRange(l+p,i(h,0))}else{var m=0==o(s.getCursor("to"),r),g=!s.somethingSelected();s.replaceRange(d,r),m&&s.setSelection(g?r:s.getCursor("from"),r),s.replaceRange(c,e)}}))}}else(a.lineComment||u.lineComment)&&0!=a.fullLines&&s.lineComment(e,r,a)})),e.defineExtension("uncomment",(function(e,r,o){o||(o=t);var a,s=this,u=l(s,e),c=Math.min(0!=r.ch||r.line==e.line?r.line:r.line-1,s.lastLine()),d=Math.min(e.line,c),f=o.lineComment||u.lineComment,p=[],h=null==o.padding?" ":o.padding;e:if(f){for(var m=d;m<=c;++m){var g=s.getLine(m),v=g.indexOf(f);if(v>-1&&!/comment/.test(s.getTokenTypeAt(i(m,v+1)))&&(v=-1),-1==v&&n.test(g))break e;if(v>-1&&n.test(g.slice(0,v)))break e;p.push(g)}if(s.operation((function(){for(var e=d;e<=c;++e){var t=p[e-d],n=t.indexOf(f),r=n+f.length;n<0||(t.slice(r,r+h.length)==h&&(r+=h.length),a=!0,s.replaceRange("",i(e,n),i(e,r)))}})),a)return!0}var y=o.blockCommentStart||u.blockCommentStart,b=o.blockCommentEnd||u.blockCommentEnd;if(!y||!b)return!1;var E=o.blockCommentLead||u.blockCommentLead,T=s.getLine(d),w=T.indexOf(y);if(-1==w)return!1;var C=c==d?T:s.getLine(c),S=C.indexOf(b,c==d?w+y.length:0),x=i(d,w+1),k=i(c,S+1);if(-1==S||!/comment/.test(s.getTokenTypeAt(x))||!/comment/.test(s.getTokenTypeAt(k))||s.getRange(x,k,"\n").indexOf(b)>-1)return!1;var N=T.lastIndexOf(y,e.ch),_=-1==N?-1:T.slice(0,e.ch).indexOf(b,N+y.length);if(-1!=N&&-1!=_&&_+b.length!=e.ch)return!1;_=C.indexOf(b,r.ch);var O=C.slice(r.ch).lastIndexOf(y,_-r.ch);return N=-1==_||-1==O?-1:r.ch+O,(-1==_||-1==N||N==r.ch)&&(s.operation((function(){s.replaceRange("",i(c,S-(h&&C.slice(S-h.length,S)==h?h.length:0)),i(c,S+b.length));var e=w+y.length;if(h&&T.slice(e,e+h.length)==h&&(e+=h.length),s.replaceRange("",i(d,w),i(d,e)),E)for(var t=d+1;t<=c;++t){var r=s.getLine(t),o=r.indexOf(E);if(-1!=o&&!n.test(r.slice(0,o))){var a=o+E.length;h&&r.slice(a,a+h.length)==h&&(a+=h.length),s.replaceRange("",i(t,o),i(t,a))}}})),!0)}))}(t.a.exports);var a=i({__proto__:null,default:o.exports},[o.exports]);e.c=a})?r.apply(t,i):r)||(e.exports=o)},8058:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[t,n(535)],void 0===(o="function"==typeof(r=function(e,t){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.d=e.a=void 0;var n=Object.defineProperty,r=(e,t)=>n(e,"name",{value:t,configurable:!0});function i(e,t){return t.forEach((function(t){t&&"string"!=typeof t&&!Array.isArray(t)&&Object.keys(t).forEach((function(n){if("default"!==n&&!(n in e)){var r=Object.getOwnPropertyDescriptor(t,n);Object.defineProperty(e,n,r.get?r:{enumerable:!0,get:function(){return t[n]}})}}))})),Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}r(i,"_mergeNamespaces");var o={exports:{}};e.a=o,function(e){function t(t,n,r){var i,o=t.getWrapperElement();return(i=o.appendChild(document.createElement("div"))).className=r?"CodeMirror-dialog CodeMirror-dialog-bottom":"CodeMirror-dialog CodeMirror-dialog-top","string"==typeof n?i.innerHTML=n:i.appendChild(n),e.addClass(o,"dialog-opened"),i}function n(e,t){e.state.currentNotificationClose&&e.state.currentNotificationClose(),e.state.currentNotificationClose=t}r(t,"dialogDiv"),r(n,"closeNotification"),e.defineExtension("openDialog",(function(i,o,a){a||(a={}),n(this,null);var s=t(this,i,a.bottom),l=!1,u=this;function c(t){if("string"==typeof t)f.value=t;else{if(l)return;l=!0,e.rmClass(s.parentNode,"dialog-opened"),s.parentNode.removeChild(s),u.focus(),a.onClose&&a.onClose(s)}}r(c,"close");var d,f=s.getElementsByTagName("input")[0];return f?(f.focus(),a.value&&(f.value=a.value,!1!==a.selectValueOnOpen&&f.select()),a.onInput&&e.on(f,"input",(function(e){a.onInput(e,f.value,c)})),a.onKeyUp&&e.on(f,"keyup",(function(e){a.onKeyUp(e,f.value,c)})),e.on(f,"keydown",(function(t){a&&a.onKeyDown&&a.onKeyDown(t,f.value,c)||((27==t.keyCode||!1!==a.closeOnEnter&&13==t.keyCode)&&(f.blur(),e.e_stop(t),c()),13==t.keyCode&&o(f.value,t))})),!1!==a.closeOnBlur&&e.on(s,"focusout",(function(e){null!==e.relatedTarget&&c()}))):(d=s.getElementsByTagName("button")[0])&&(e.on(d,"click",(function(){c(),u.focus()})),!1!==a.closeOnBlur&&e.on(d,"blur",c),d.focus()),c})),e.defineExtension("openConfirm",(function(i,o,a){n(this,null);var s=t(this,i,a&&a.bottom),l=s.getElementsByTagName("button"),u=!1,c=this,d=1;function f(){u||(u=!0,e.rmClass(s.parentNode,"dialog-opened"),s.parentNode.removeChild(s),c.focus())}r(f,"close"),l[0].focus();for(var p=0;pn(e,"name",{value:t,configurable:!0});function i(e,t){return t.forEach((function(t){t&&"string"!=typeof t&&!Array.isArray(t)&&Object.keys(t).forEach((function(n){if("default"!==n&&!(n in e)){var r=Object.getOwnPropertyDescriptor(t,n);Object.defineProperty(e,n,r.get?r:{enumerable:!0,get:function(){return t[n]}})}}))})),Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}r(i,"_mergeNamespaces");var o={exports:{}};!function(e){function t(t,i,a,s){if(a&&a.call){var l=a;a=null}else l=o(t,a,"rangeFinder");"number"==typeof i&&(i=e.Pos(i,0));var u=o(t,a,"minFoldSize");function c(e){var n=l(t,i);if(!n||n.to.line-n.from.linet.firstLine();)i=e.Pos(i.line-1,0),d=c(!1);if(d&&!d.cleared&&"unfold"!==s){var f=n(t,a,d);e.on(f,"mousedown",(function(t){p.clear(),e.e_preventDefault(t)}));var p=t.markText(d.from,d.to,{replacedWith:f,clearOnEnter:o(t,a,"clearOnEnter"),__isFold:!0});p.on("clear",(function(n,r){e.signal(t,"unfold",t,n,r)})),e.signal(t,"fold",t,d.from,d.to)}}function n(e,t,n){var r=o(e,t,"widget");if("function"==typeof r&&(r=r(n.from,n.to)),"string"==typeof r){var i=document.createTextNode(r);(r=document.createElement("span")).appendChild(i),r.className="CodeMirror-foldmarker"}else r&&(r=r.cloneNode(!0));return r}r(t,"doFold"),r(n,"makeWidget"),e.newFoldFunction=function(e,n){return function(r,i){t(r,i,{rangeFinder:e,widget:n})}},e.defineExtension("foldCode",(function(e,n,r){t(this,e,n,r)})),e.defineExtension("isFolded",(function(e){for(var t=this.findMarksAt(e),n=0;n=u){if(f&&l&&f.test(l.className))return;r=a(i.indicatorOpen)}}(r||l)&&e.setGutterMarker(n,i.gutter,r)}))}function l(e){return new RegExp("(^|\\s)"+e+"(?:$|\\s)\\s*")}function u(e){var t=e.getViewport(),n=e.state.foldGutter;n&&(e.operation((function(){s(e,t.from,t.to)})),n.from=t.from,n.to=t.to)}function c(e,n,r){var i=e.state.foldGutter;if(i){var a=i.options;if(r==a.gutter){var s=o(e,n);s?s.clear():e.foldCode(t(n,0),a)}}}function d(e){var t=e.state.foldGutter;if(t){var n=t.options;t.from=t.to=0,clearTimeout(t.changeUpdate),t.changeUpdate=setTimeout((function(){u(e)}),n.foldOnChangeTimeSpan||600)}}function f(e){var t=e.state.foldGutter;if(t){var n=t.options;clearTimeout(t.changeUpdate),t.changeUpdate=setTimeout((function(){var n=e.getViewport();t.from==t.to||n.from-t.to>20||t.from-n.to>20?u(e):e.operation((function(){n.fromt.to&&(s(e,t.to,n.to),t.to=n.to)}))}),n.updateViewportTimeSpan||400)}}function p(e,t){var n=e.state.foldGutter;if(n){var r=t.line;r>=n.from&&r=0;e--)t(n[e])}Object.defineProperty(e,"__esModule",{value:!0}),e.f=t,(0,Object.defineProperty)(t,"name",{value:"forEachState",configurable:!0})})?n.apply(t,[t]):n)||(e.exports=r)},7139:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[t,n(6856),n(9196),n(3573),n(1850)],void 0===(o="function"==typeof(r=function(e,t,n,r,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),Object.defineProperty(e,"Argument",{enumerable:!0,get:function(){return t.A}}),Object.defineProperty(e,"ArgumentIcon",{enumerable:!0,get:function(){return t.ac}}),Object.defineProperty(e,"Button",{enumerable:!0,get:function(){return t.aH}}),Object.defineProperty(e,"ButtonGroup",{enumerable:!0,get:function(){return t.aI}}),Object.defineProperty(e,"ChevronDownIcon",{enumerable:!0,get:function(){return t.ad}}),Object.defineProperty(e,"ChevronLeftIcon",{enumerable:!0,get:function(){return t.ae}}),Object.defineProperty(e,"ChevronUpIcon",{enumerable:!0,get:function(){return t.af}}),Object.defineProperty(e,"CloseIcon",{enumerable:!0,get:function(){return t.ag}}),Object.defineProperty(e,"CopyIcon",{enumerable:!0,get:function(){return t.ah}}),Object.defineProperty(e,"DOC_EXPLORER_PLUGIN",{enumerable:!0,get:function(){return t._}}),Object.defineProperty(e,"DefaultValue",{enumerable:!0,get:function(){return t.D}}),Object.defineProperty(e,"DeprecatedArgumentIcon",{enumerable:!0,get:function(){return t.ai}}),Object.defineProperty(e,"DeprecatedEnumValueIcon",{enumerable:!0,get:function(){return t.aj}}),Object.defineProperty(e,"DeprecatedFieldIcon",{enumerable:!0,get:function(){return t.ak}}),Object.defineProperty(e,"DeprecationReason",{enumerable:!0,get:function(){return t.w}}),Object.defineProperty(e,"Dialog",{enumerable:!0,get:function(){return t.aJ}}),Object.defineProperty(e,"Directive",{enumerable:!0,get:function(){return t.x}}),Object.defineProperty(e,"DirectiveIcon",{enumerable:!0,get:function(){return t.al}}),Object.defineProperty(e,"DocExplorer",{enumerable:!0,get:function(){return t.y}}),Object.defineProperty(e,"DocsFilledIcon",{enumerable:!0,get:function(){return t.am}}),Object.defineProperty(e,"DocsIcon",{enumerable:!0,get:function(){return t.an}}),Object.defineProperty(e,"EditorContext",{enumerable:!0,get:function(){return t.E}}),Object.defineProperty(e,"EditorContextProvider",{enumerable:!0,get:function(){return t.d}}),Object.defineProperty(e,"EnumValueIcon",{enumerable:!0,get:function(){return t.ao}}),Object.defineProperty(e,"ExecuteButton",{enumerable:!0,get:function(){return t.aS}}),Object.defineProperty(e,"ExecutionContext",{enumerable:!0,get:function(){return t.r}}),Object.defineProperty(e,"ExecutionContextProvider",{enumerable:!0,get:function(){return t.s}}),Object.defineProperty(e,"ExplorerContext",{enumerable:!0,get:function(){return t.z}}),Object.defineProperty(e,"ExplorerContextProvider",{enumerable:!0,get:function(){return t.B}}),Object.defineProperty(e,"ExplorerSection",{enumerable:!0,get:function(){return t.F}}),Object.defineProperty(e,"FieldDocumentation",{enumerable:!0,get:function(){return t.G}}),Object.defineProperty(e,"FieldIcon",{enumerable:!0,get:function(){return t.ap}}),Object.defineProperty(e,"FieldLink",{enumerable:!0,get:function(){return t.J}}),Object.defineProperty(e,"GraphiQLProvider",{enumerable:!0,get:function(){return t.a3}}),Object.defineProperty(e,"HISTORY_PLUGIN",{enumerable:!0,get:function(){return t.$}}),Object.defineProperty(e,"HeaderEditor",{enumerable:!0,get:function(){return t.H}}),Object.defineProperty(e,"History",{enumerable:!0,get:function(){return t.W}}),Object.defineProperty(e,"HistoryContext",{enumerable:!0,get:function(){return t.X}}),Object.defineProperty(e,"HistoryContextProvider",{enumerable:!0,get:function(){return t.Y}}),Object.defineProperty(e,"HistoryIcon",{enumerable:!0,get:function(){return t.aq}}),Object.defineProperty(e,"ImagePreview",{enumerable:!0,get:function(){return t.I}}),Object.defineProperty(e,"ImplementsIcon",{enumerable:!0,get:function(){return t.ar}}),Object.defineProperty(e,"KeyboardShortcutIcon",{enumerable:!0,get:function(){return t.as}}),Object.defineProperty(e,"Listbox",{enumerable:!0,get:function(){return t.aL}}),Object.defineProperty(e,"MagnifyingGlassIcon",{enumerable:!0,get:function(){return t.at}}),Object.defineProperty(e,"MarkdownContent",{enumerable:!0,get:function(){return t.aM}}),Object.defineProperty(e,"Menu",{enumerable:!0,get:function(){return t.aK}}),Object.defineProperty(e,"MergeIcon",{enumerable:!0,get:function(){return t.au}}),Object.defineProperty(e,"PenIcon",{enumerable:!0,get:function(){return t.av}}),Object.defineProperty(e,"PlayIcon",{enumerable:!0,get:function(){return t.aw}}),Object.defineProperty(e,"PluginContext",{enumerable:!0,get:function(){return t.a0}}),Object.defineProperty(e,"PluginContextProvider",{enumerable:!0,get:function(){return t.a1}}),Object.defineProperty(e,"PlusIcon",{enumerable:!0,get:function(){return t.ax}}),Object.defineProperty(e,"PrettifyIcon",{enumerable:!0,get:function(){return t.ay}}),Object.defineProperty(e,"QueryEditor",{enumerable:!0,get:function(){return t.Q}}),Object.defineProperty(e,"ReloadIcon",{enumerable:!0,get:function(){return t.az}}),Object.defineProperty(e,"ResponseEditor",{enumerable:!0,get:function(){return t.R}}),Object.defineProperty(e,"RootTypeIcon",{enumerable:!0,get:function(){return t.aA}}),Object.defineProperty(e,"SchemaContext",{enumerable:!0,get:function(){return t.a4}}),Object.defineProperty(e,"SchemaContextProvider",{enumerable:!0,get:function(){return t.a5}}),Object.defineProperty(e,"SchemaDocumentation",{enumerable:!0,get:function(){return t.K}}),Object.defineProperty(e,"Search",{enumerable:!0,get:function(){return t.M}}),Object.defineProperty(e,"SettingsIcon",{enumerable:!0,get:function(){return t.aB}}),Object.defineProperty(e,"Spinner",{enumerable:!0,get:function(){return t.aN}}),Object.defineProperty(e,"StarFilledIcon",{enumerable:!0,get:function(){return t.aC}}),Object.defineProperty(e,"StarIcon",{enumerable:!0,get:function(){return t.aD}}),Object.defineProperty(e,"StopIcon",{enumerable:!0,get:function(){return t.aE}}),Object.defineProperty(e,"StorageContext",{enumerable:!0,get:function(){return t.a7}}),Object.defineProperty(e,"StorageContextProvider",{enumerable:!0,get:function(){return t.a8}}),Object.defineProperty(e,"Tab",{enumerable:!0,get:function(){return t.aO}}),Object.defineProperty(e,"Tabs",{enumerable:!0,get:function(){return t.aP}}),Object.defineProperty(e,"ToolbarButton",{enumerable:!0,get:function(){return t.aR}}),Object.defineProperty(e,"ToolbarListbox",{enumerable:!0,get:function(){return t.aT}}),Object.defineProperty(e,"ToolbarMenu",{enumerable:!0,get:function(){return t.aU}}),Object.defineProperty(e,"Tooltip",{enumerable:!0,get:function(){return t.aQ}}),Object.defineProperty(e,"TypeDocumentation",{enumerable:!0,get:function(){return t.N}}),Object.defineProperty(e,"TypeIcon",{enumerable:!0,get:function(){return t.aF}}),Object.defineProperty(e,"TypeLink",{enumerable:!0,get:function(){return t.O}}),Object.defineProperty(e,"UnStyledButton",{enumerable:!0,get:function(){return t.aG}}),Object.defineProperty(e,"VariableEditor",{enumerable:!0,get:function(){return t.V}}),Object.defineProperty(e,"useAutoCompleteLeafs",{enumerable:!0,get:function(){return t.u}}),Object.defineProperty(e,"useCopyQuery",{enumerable:!0,get:function(){return t.e}}),Object.defineProperty(e,"useDragResize",{enumerable:!0,get:function(){return t.ab}}),Object.defineProperty(e,"useEditorContext",{enumerable:!0,get:function(){return t.f}}),Object.defineProperty(e,"useExecutionContext",{enumerable:!0,get:function(){return t.v}}),Object.defineProperty(e,"useExplorerContext",{enumerable:!0,get:function(){return t.U}}),Object.defineProperty(e,"useHeaderEditor",{enumerable:!0,get:function(){return t.h}}),Object.defineProperty(e,"useHistoryContext",{enumerable:!0,get:function(){return t.Z}}),Object.defineProperty(e,"useMergeQuery",{enumerable:!0,get:function(){return t.j}}),Object.defineProperty(e,"usePluginContext",{enumerable:!0,get:function(){return t.a2}}),Object.defineProperty(e,"usePrettifyEditors",{enumerable:!0,get:function(){return t.k}}),Object.defineProperty(e,"useQueryEditor",{enumerable:!0,get:function(){return t.m}}),Object.defineProperty(e,"useResponseEditor",{enumerable:!0,get:function(){return t.n}}),Object.defineProperty(e,"useSchemaContext",{enumerable:!0,get:function(){return t.a6}}),Object.defineProperty(e,"useStorageContext",{enumerable:!0,get:function(){return t.a9}}),Object.defineProperty(e,"useTheme",{enumerable:!0,get:function(){return t.aa}}),Object.defineProperty(e,"useVariableEditor",{enumerable:!0,get:function(){return t.q}})})?r.apply(t,i):r)||(e.exports=o)},4840:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[n(535),n(6980),n(3573),n(6856),n(5609),n(9196),n(1850)],void 0===(o="function"==typeof(r=function(e,t,n,r,i,o,a){"use strict";e.C.registerHelper("hint","graphql",((t,n)=>{const{schema:o,externalFragments:a}=n;if(!o)return;const s=t.getCursor(),l=t.getTokenAt(s),u=null!==l.type&&/"|\w/.test(l.string[0])?l.start:l.end,c=new i.P(s.line,u),d={list:(0,r.g)(o,t.getValue(),c,l,a).map((e=>({text:e.label,type:e.type,description:e.documentation,isDeprecated:e.isDeprecated,deprecationReason:e.deprecationReason}))),from:{line:s.line,ch:u},to:{line:s.line,ch:l.end}};return(null==d?void 0:d.list)&&d.list.length>0&&(d.from=e.C.Pos(d.from.line,d.from.ch),d.to=e.C.Pos(d.to.line,d.to.ch),e.C.signal(t,"hasCompletion",t,d,l)),d}))})?r.apply(t,i):r)||(e.exports=o)},4712:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[n(535),n(3573),n(2635),n(6856),n(9196),n(1850)],void 0===(o="function"==typeof(r=function(e,t,n,r,i,o){"use strict";var a=Object.defineProperty,s=(e,t)=>a(e,"name",{value:t,configurable:!0});function l(e,t,n){const r=u(n,d(t.string));if(!r)return;const i=null!==t.type&&/"|\w/.test(t.string[0])?t.start:t.end;return{list:r,from:{line:e.line,ch:i},to:{line:e.line,ch:t.end}}}function u(e,t){return t?c(c(e.map((e=>({proximity:f(d(e.text),t),entry:e}))),(e=>e.proximity<=2)),(e=>!e.entry.isDeprecated)).sort(((e,t)=>(e.entry.isDeprecated?1:0)-(t.entry.isDeprecated?1:0)||e.proximity-t.proximity||e.entry.text.length-t.entry.text.length)).map((e=>e.entry)):c(e,(e=>!e.isDeprecated))}function c(e,t){const n=e.filter(t);return 0===n.length?e:n}function d(e){return e.toLowerCase().replaceAll(/\W/g,"")}function f(e,t){let n=p(t,e);return e.length>t.length&&(n-=e.length-t.length-1,n+=0===e.indexOf(t)?0:.5),n}function p(e,t){let n,r;const i=[],o=e.length,a=t.length;for(n=0;n<=o;n++)i[n]=[n];for(r=1;r<=a;r++)i[0][r]=r;for(n=1;n<=o;n++)for(r=1;r<=a;r++){const o=e[n-1]===t[r-1]?0:1;i[n][r]=Math.min(i[n-1][r]+1,i[n][r-1]+1,i[n-1][r-1]+o),n>1&&r>1&&e[n-1]===t[r-2]&&e[n-2]===t[r-1]&&(i[n][r]=Math.min(i[n][r],i[n-2][r-2]+o))}return i[o][a]}function h(e,n,r){const i="Invalid"===n.state.kind?n.state.prevState:n.state,{kind:o,step:a}=i;if("Document"===o&&0===a)return l(e,n,[{text:"{"}]);const{variableToType:s}=r;if(!s)return;const u=m(s,n.state);if("Document"===o||"Variable"===o&&0===a)return l(e,n,Object.keys(s).map((e=>({text:`"${e}": `,type:s[e]}))));if(("ObjectValue"===o||"ObjectField"===o&&0===a)&&u.fields)return l(e,n,Object.keys(u.fields).map((e=>u.fields[e])).map((e=>({text:`"${e.name}": `,type:e.type,description:e.description}))));if("StringValue"===o||"NumberValue"===o||"BooleanValue"===o||"NullValue"===o||"ListValue"===o&&1===a||"ObjectField"===o&&2===a||"Variable"===o&&2===a){const r=u.type?(0,t.getNamedType)(u.type):void 0;if(r instanceof t.GraphQLInputObjectType)return l(e,n,[{text:"{"}]);if(r instanceof t.GraphQLEnumType)return l(e,n,r.getValues().map((e=>({text:`"${e.name}"`,type:r,description:e.description}))));if(r===t.GraphQLBoolean)return l(e,n,[{text:"true",type:t.GraphQLBoolean,description:"Not false."},{text:"false",type:t.GraphQLBoolean,description:"Not true."}])}}function m(e,r){const i={type:null,fields:null};return(0,n.f)(r,(n=>{switch(n.kind){case"Variable":i.type=e[n.name];break;case"ListValue":{const e=i.type?(0,t.getNullableType)(i.type):void 0;i.type=e instanceof t.GraphQLList?e.ofType:null;break}case"ObjectValue":{const e=i.type?(0,t.getNamedType)(i.type):void 0;i.fields=e instanceof t.GraphQLInputObjectType?e.getFields():null;break}case"ObjectField":{const e=n.name&&i.fields?i.fields[n.name]:null;i.type=null==e?void 0:e.type;break}}})),i}s(l,"hintList"),s(u,"filterAndSortList"),s(c,"filterNonEmpty"),s(d,"normalizeText"),s(f,"getProximity"),s(p,"lexicalDistance"),e.C.registerHelper("hint","graphql-variables",((t,n)=>{const r=t.getCursor(),i=t.getTokenAt(r),o=h(r,i,n);return(null==o?void 0:o.list)&&o.list.length>0&&(o.from=e.C.Pos(o.from.line,o.from.ch),o.to=e.C.Pos(o.to.line,o.to.ch),e.C.signal(t,"hasCompletion",t,o,i)),o})),s(h,"getVariablesHint"),s(m,"getTypeInfo")})?r.apply(t,i):r)||(e.exports=o)},6856:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[t,n(9196),n(3573),n(1850)],r=function(e,t,r,i){"use strict";function o(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(o=function(e){return e?n:t})(e)}function a(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=o(t);if(n&&n.has(e))return n.get(e);var r={},i=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var a in e)if("default"!==a&&Object.prototype.hasOwnProperty.call(e,a)){var s=i?Object.getOwnPropertyDescriptor(e,a):null;s&&(s.get||s.set)?Object.defineProperty(r,a,s):r[a]=e[a]}return r.default=e,n&&n.set(e,r),r}Object.defineProperty(e,"__esModule",{value:!0}),e.$=void 0,e.A=JE,e.B=$E,e.C=void 0,e.D=IE,e.E=void 0,e.F=sT,e.G=dT,e.H=cS,e.I=pS,e.J=Lw,e.K=gT,e.L=void 0,e.M=xw,e.N=Rw,e.O=QE,e.P=void 0,e.Q=yS,e.R=SS,e.U=e.T=e.S=void 0,e.V=NS,e.W=oE,e.X=void 0,e.Y=eE,e.a0=e.a=e._=e.Z=void 0,e.a1=Xw,e.a2=void 0,e.a3=IS,e.a4=void 0,e.a5=ME,e.a7=e.a6=void 0,e.a8=ve,e.aR=e.aQ=e.aP=e.aO=e.aN=e.aM=e.aL=e.aK=e.aJ=e.aI=e.aH=e.aG=e.aF=e.aE=e.aD=e.aC=e.aB=e.aA=e.a9=void 0,e.aS=HS,e.aU=e.aT=void 0,e.aa=AS,e.ab=PS,e.az=e.ay=e.ax=e.aw=e.av=e.au=e.at=e.as=e.ar=e.aq=e.ap=e.ao=e.an=e.am=e.al=e.ak=e.aj=e.ai=e.ah=e.ag=e.af=e.ae=e.ad=e.ac=void 0,e.b=_i,e.c=void 0,e.d=iS,e.e=uC,e.f=void 0,e.g=eo,e.h=mC,e.i=void 0,e.j=cC,e.k=dC,e.l=Oi,e.m=SC,e.n=TS,e.o=Vi,e.p=Li,e.q=ZC,e.r=void 0,e.s=dE,e.t=Di,e.u=fC,e.v=void 0,e.w=tT,e.x=iT,e.y=Hw,e.z=void 0,t=a(t),i=a(i);var s=Object.defineProperty,l=Object.defineProperties,u=Object.getOwnPropertyDescriptors,c=Object.getOwnPropertySymbols,d=Object.prototype.hasOwnProperty,f=Object.prototype.propertyIsEnumerable,p=(e,t,n)=>t in e?s(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n,h=(e,t)=>{for(var n in t||(t={}))d.call(t,n)&&p(e,n,t[n]);if(c)for(var n of c(t))f.call(t,n)&&p(e,n,t[n]);return e},m=(e,t)=>l(e,u(t)),g=(e,t)=>s(e,"name",{value:t,configurable:!0}),v=(e,t)=>{var n={};for(var r in e)d.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(null!=e&&c)for(var r of c(e))t.indexOf(r)<0&&f.call(e,r)&&(n[r]=e[r]);return n};function y(e){var t,n,r="";if("string"==typeof e||"number"==typeof e)r+=e;else if("object"==typeof e)if(Array.isArray(e))for(t=0;t{const r=e.subscribe({next:e=>{t(e),r.unsubscribe()},error:n,complete:()=>{n(new Error("no value resolved"))}})}))}function C(e){return"object"==typeof e&&null!==e&&"subscribe"in e&&"function"==typeof e.subscribe}function S(e){return"object"==typeof e&&null!==e&&("AsyncGenerator"===e[Symbol.toStringTag]||Symbol.asyncIterator in e)}function x(e){var t;return E(this,void 0,void 0,(function*(){const n=null===(t=("return"in e?e:e[Symbol.asyncIterator]()).return)||void 0===t?void 0:t.bind(e),r=("next"in e?e:e[Symbol.asyncIterator]()).next.bind(e),i=yield r();return null==n||n(),i.value}))}function k(e){return E(this,void 0,void 0,(function*(){const t=yield e;return S(t)?x(t):C(t)?w(t):t}))}g(T,"isPromise"),g(w,"observableToPromise"),g(C,"isObservable"),g(S,"isAsyncIterable"),g(x,"asyncIterableToPromise"),g(k,"fetcherReturnToPromise"),globalThis&&globalThis.__awaiter;var N=globalThis&&globalThis.__await||function(e){return this instanceof N?(this.v=e,this):new N(e)};function _(e){return JSON.stringify(e,null,2)}function O(e){return Object.assign(Object.assign({},e),{message:e.message,stack:e.stack})}function I(e){return e instanceof Error?O(e):e}function D(e){return Array.isArray(e)?_({errors:e.map((e=>I(e)))}):_({errors:[I(e)]})}function L(e){return _(e)}function A(e,t,n){const i=[];if(!e||!t)return{insertions:i,result:t};let o;try{o=(0,r.parse)(t)}catch(e){return{insertions:i,result:t}}const a=n||M,s=new r.TypeInfo(e);return(0,r.visit)(o,{leave(e){s.leave(e)},enter(e){if(s.enter(e),"Field"===e.kind&&!e.selectionSet){const n=R(j(s.getType()),a);if(n&&e.loc){const o=P(t,e.loc.start);i.push({index:e.loc.end,string:" "+(0,r.print)(n).replaceAll("\n","\n"+o)})}}}}),{insertions:i,result:F(t,i)}}function M(e){if(!("getFields"in e))return[];const t=e.getFields();if(t.id)return["id"];if(t.edges)return["edges"];if(t.node)return["node"];const n=[];for(const e of Object.keys(t))(0,r.isLeafType)(t[e].type)&&n.push(e);return n}function R(e,t){const n=(0,r.getNamedType)(e);if(!e||(0,r.isLeafType)(e))return;const i=t(n);return Array.isArray(i)&&0!==i.length&&"getFields"in n?{kind:r.Kind.SELECTION_SET,selections:i.map((e=>{const i=n.getFields()[e],o=i?i.type:null;return{kind:r.Kind.FIELD,name:{kind:r.Kind.NAME,value:e},selectionSet:R(o,t)}}))}:void 0}function F(e,t){if(0===t.length)return e;let n="",r=0;for(const{index:i,string:o}of t)n+=e.slice(r,i)+o,r=i;return n+=e.slice(r),n}function P(e,t){let n=t,r=t;for(;n;){const t=e.charCodeAt(n-1);if(10===t||13===t||8232===t||8233===t)break;n--,9!==t&&11!==t&&12!==t&&32!==t&&160!==t&&(r=n)}return e.slice(n,r)}function j(e){if(e)return e}function V(e,t){var n;const r=new Map,i=[];for(const o of e)if("Field"===o.kind){const e=t(o),a=r.get(e);if(null===(n=o.directives)||void 0===n?void 0:n.length){const e=Object.assign({},o);i.push(e)}else if((null==a?void 0:a.selectionSet)&&o.selectionSet)a.selectionSet.selections=[...a.selectionSet.selections,...o.selectionSet.selections];else if(!a){const t=Object.assign({},o);r.set(e,t),i.push(t)}}else i.push(o);return i}function U(e,t,n){var i;const o=n?(0,r.getNamedType)(n).name:null,a=[],s=[];for(let l of t){if("FragmentSpread"===l.kind){const t=l.name.value;if(!l.directives||0===l.directives.length){if(s.includes(t))continue;s.push(t)}const n=e[l.name.value];if(n){const{typeCondition:e,directives:t,selectionSet:i}=n;l={kind:r.Kind.INLINE_FRAGMENT,typeCondition:e,directives:t,selectionSet:i}}}if(l.kind===r.Kind.INLINE_FRAGMENT&&(!l.directives||0===(null===(i=l.directives)||void 0===i?void 0:i.length))){const t=l.typeCondition?l.typeCondition.name.value:null;if(!t||t===o){a.push(...U(e,l.selectionSet.selections,n));continue}}a.push(l)}return a}function B(e,t){const n=t?new r.TypeInfo(t):null,i=Object.create(null);for(const t of e.definitions)t.kind===r.Kind.FRAGMENT_DEFINITION&&(i[t.name.value]=t);const o={SelectionSet(e){const t=n?n.getParentType():null;let{selections:r}=e;return r=U(i,r,t),r=V(r,(e=>e.alias?e.alias.value:e.name.value)),Object.assign(Object.assign({},e),{selections:r})},FragmentDefinition(){return null}};return(0,r.visit)(e,n?(0,r.visitWithTypeInfo)(n,o):o)}function $(e,t,n){if(!n||n.length<1)return;const r=n.map((e=>{var t;return null===(t=e.name)||void 0===t?void 0:t.value}));if(t&&r.includes(t))return t;if(t&&e){const n=e.map((e=>{var t;return null===(t=e.name)||void 0===t?void 0:t.value})).indexOf(t);if(-1!==n&&n{for(const e in window.localStorage)0===e.indexOf(`${G}:`)&&window.localStorage.removeItem(e)}}}get(e){if(!this.storage)return null;const t=`${G}:${e}`,n=this.storage.getItem(t);return"null"===n||"undefined"===n?(this.storage.removeItem(t),null):n||null}set(e,t){let n=!1,r=null;if(this.storage){const i=`${G}:${e}`;if(t)try{this.storage.setItem(i,t)}catch(e){r=e instanceof Error?e:new Error(`${e}`),n=q(this.storage,e)}else this.storage.removeItem(i)}return{isQuotaError:n,error:r}}clear(){this.storage&&this.storage.clear()}}g(H,"StorageAPI");const G="graphiql";class z{constructor(e,t){let n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;this.key=e,this.storage=t,this.maxSize=n,this.items=this.fetchAll()}get length(){return this.items.length}contains(e){return this.items.some((t=>t.query===e.query&&t.variables===e.variables&&t.headers===e.headers&&t.operationName===e.operationName))}edit(e){const t=this.items.findIndex((t=>t.query===e.query&&t.variables===e.variables&&t.headers===e.headers&&t.operationName===e.operationName));-1!==t&&(this.items.splice(t,1,e),this.save())}delete(e){const t=this.items.findIndex((t=>t.query===e.query&&t.variables===e.variables&&t.headers===e.headers&&t.operationName===e.operationName));-1!==t&&(this.items.splice(t,1),this.save())}fetchRecent(){return this.items.at(-1)}fetchAll(){const e=this.storage.get(this.key);return e?JSON.parse(e)[this.key]:[]}push(e){const t=[...this.items,e];this.maxSize&&t.length>this.maxSize&&t.shift();for(let e=0;e<5;e++){const e=this.storage.set(this.key,JSON.stringify({[this.key]:t}));if(null==e?void 0:e.error){if(!e.isQuotaError||!this.maxSize)return;t.shift()}else this.items=t}}save(){this.storage.set(this.key,JSON.stringify({[this.key]:this.items}))}}g(z,"QueryStore");class W{constructor(e,t){this.storage=e,this.maxHistoryLength=t,this.updateHistory=(e,t,n,r)=>{if(this.shouldSaveQuery(e,t,n,this.history.fetchRecent())){this.history.push({query:e,variables:t,headers:n,operationName:r});const i=this.history.items,o=this.favorite.items;this.queries=i.concat(o)}},this.history=new z("queries",this.storage,this.maxHistoryLength),this.favorite=new z("favorites",this.storage,null),this.queries=[...this.history.fetchAll(),...this.favorite.fetchAll()]}shouldSaveQuery(e,t,n,i){if(!e)return!1;try{(0,r.parse)(e)}catch(e){return!1}if(e.length>1e5)return!1;if(!i)return!0;if(JSON.stringify(e)===JSON.stringify(i.query)){if(JSON.stringify(t)===JSON.stringify(i.variables)){if(JSON.stringify(n)===JSON.stringify(i.headers))return!1;if(n&&!i.headers)return!1}if(t&&!i.variables)return!1}return!0}toggleFavorite(e,t,n,r,i,o){const a={query:e,variables:t,headers:n,operationName:r,label:i};this.favorite.contains(a)?o&&(a.favorite=!1,this.favorite.delete(a)):(a.favorite=!0,this.favorite.push(a)),this.queries=[...this.history.items,...this.favorite.items]}editLabel(e,t,n,r,i,o){const a={query:e,variables:t,headers:n,operationName:r,label:i};o?this.favorite.edit(Object.assign(Object.assign({},a),{favorite:o})):this.history.edit(a),this.queries=[...this.history.items,...this.favorite.items]}}g(W,"HistoryStore");var K=Object.defineProperty,Q=g(((e,t)=>K(e,"name",{value:t,configurable:!0})),"__name$G");function X(e){const n=(0,t.createContext)(null);return n.displayName=e,n}function Y(e){function n(r){var i;const o=(0,t.useContext)(e);if(null===o&&(null==r?void 0:r.nonNull))throw new Error(`Tried to use \`${(null==(i=r.caller)?void 0:i.name)||n.caller.name}\` without the necessary context. Make sure to render the \`${e.displayName}Provider\` component higher up the tree.`);return o}return g(n,"useGivenContext"),Q(n,"useGivenContext"),Object.defineProperty(n,"name",{value:`use${e.displayName}`}),n}g(X,"createNullableContext"),Q(X,"createNullableContext"),g(Y,"createContextHook"),Q(Y,"createContextHook");var J="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:void 0!==n.g?n.g:"undefined"!=typeof self?self:{};function Z(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}function ee(e){if(e.__esModule)return e;var t=Object.defineProperty({},"__esModule",{value:!0});return Object.keys(e).forEach((function(n){var r=Object.getOwnPropertyDescriptor(e,n);Object.defineProperty(t,n,r.get?r:{enumerable:!0,get:function(){return e[n]}})})),t}e.c=J,g(Z,"getDefaultExportFromCjs"),g(ee,"getAugmentedNamespace");var te={exports:{}},ne={};function re(){try{if(!Object.assign)return!1;var e=new String("abc");if(e[5]="de","5"===Object.getOwnPropertyNames(e)[0])return!1;for(var t={},n=0;n<10;n++)t["_"+String.fromCharCode(n)]=n;if("0123456789"!==Object.getOwnPropertyNames(t).map((function(e){return t[e]})).join(""))return!1;var r={};return"abcdefghijklmnopqrst".split("").forEach((function(e){r[e]=e})),"abcdefghijklmnopqrst"===Object.keys(Object.assign({},r)).join("")}catch(e){return!1}}Object.getOwnPropertySymbols,Object.prototype.hasOwnProperty,Object.prototype.propertyIsEnumerable,g((function(e){if(null==e)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(e)}),"toObject"),g(re,"shouldUseNative"),re()&&Object.assign;var ie=t.default,oe=60103;if(ne.Fragment=60107,"function"==typeof Symbol&&Symbol.for){var ae=Symbol.for;oe=ae("react.element"),ne.Fragment=ae("react.fragment")}var se=ie.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,le=Object.prototype.hasOwnProperty,ue={key:!0,ref:!0,__self:!0,__source:!0};function ce(e,t,n){var r,i={},o=null,a=null;for(r in void 0!==n&&(o=""+n),void 0!==t.key&&(o=""+t.key),void 0!==t.ref&&(a=t.ref),t)le.call(t,r)&&!ue.hasOwnProperty(r)&&(i[r]=t[r]);if(e&&e.defaultProps)for(r in t=e.defaultProps)void 0===i[r]&&(i[r]=t[r]);return{$$typeof:oe,type:e,key:o,ref:a,props:i,_owner:se.current}}g(ce,"q$1"),ne.jsx=ce,ne.jsxs=ce,te.exports=ne;const de=te.exports.jsx,fe=te.exports.jsxs,pe=te.exports.Fragment;var he=Object.defineProperty,me=g(((e,t)=>he(e,"name",{value:t,configurable:!0})),"__name$F");const ge=X("StorageContext");function ve(e){const n=(0,t.useRef)(!0),[r,i]=(0,t.useState)(new H(e.storage));return(0,t.useEffect)((()=>{n.current?n.current=!1:i(new H(e.storage))}),[e.storage]),de(ge.Provider,{value:r,children:e.children})}e.a7=ge,g(ve,"StorageContextProvider"),me(ve,"StorageContextProvider");const ye=Y(ge);e.a9=ye;const be=10,Ee=2;function Te(e){return we(e,[])}function we(e,t){switch(typeof e){case"string":return JSON.stringify(e);case"function":return e.name?`[function ${e.name}]`:"[function]";case"object":return Ce(e,t);default:return String(e)}}function Ce(e,t){if(null===e)return"null";if(t.includes(e))return"[Circular]";const n=[...t,e];if(Se(e)){const t=e.toJSON();if(t!==e)return"string"==typeof t?t:we(t,n)}else if(Array.isArray(e))return ke(e,n);return xe(e,n)}function Se(e){return"function"==typeof e.toJSON}function xe(e,t){const n=Object.entries(e);return 0===n.length?"{}":t.length>Ee?"["+Ne(e)+"]":"{ "+n.map((e=>{let[n,r]=e;return n+": "+we(r,t)})).join(", ")+" }"}function ke(e,t){if(0===e.length)return"[]";if(t.length>Ee)return"[Array]";const n=Math.min(be,e.length),r=e.length-n,i=[];for(let r=0;r1&&i.push(`... ${r} more items`),"["+i.join(", ")+"]"}function Ne(e){const t=Object.prototype.toString.call(e).replace(/^\[object /,"").replace(/]$/,"");if("Object"===t&&"function"==typeof e.constructor){const t=e.constructor.name;if("string"==typeof t&&""!==t)return t}return t}function _e(e,t){if(!Boolean(e))throw new Error(null!=t?t:"Unexpected invariant triggered.")}let Oe;function Ie(e){return 9===e||32===e}function De(e){return e>=48&&e<=57}function Le(e){return e>=97&&e<=122||e>=65&&e<=90}function Ae(e){return Le(e)||95===e}function Me(e){return Le(e)||De(e)||95===e}function Re(e,t){const n=e.replace(/"""/g,'\\"""'),r=n.split(/\r\n|[\n\r]/g),i=1===r.length,o=r.length>1&&r.slice(1).every((e=>0===e.length||Ie(e.charCodeAt(0)))),a=n.endsWith('\\"""'),s=e.endsWith('"')&&!a,l=e.endsWith("\\"),u=s||l,c=!(null!=t&&t.minimize)&&(!i||e.length>70||u||o||a);let d="";const f=i&&Ie(e.charCodeAt(0));return(c&&!f||o)&&(d+="\n"),d+=n,(c||u)&&(d+="\n"),'"""'+d+'"""'}function Fe(e){return`"${e.replace(je,Ve)}"`}var Pe;g(Te,"inspect"),g(we,"formatValue"),g(Ce,"formatObjectValue"),g(Se,"isJSONable"),g(xe,"formatObject"),g(ke,"formatArray"),g(Ne,"getObjectTag"),g(_e,"invariant"),(Pe=Oe||(Oe={})).QUERY="QUERY",Pe.MUTATION="MUTATION",Pe.SUBSCRIPTION="SUBSCRIPTION",Pe.FIELD="FIELD",Pe.FRAGMENT_DEFINITION="FRAGMENT_DEFINITION",Pe.FRAGMENT_SPREAD="FRAGMENT_SPREAD",Pe.INLINE_FRAGMENT="INLINE_FRAGMENT",Pe.VARIABLE_DEFINITION="VARIABLE_DEFINITION",Pe.SCHEMA="SCHEMA",Pe.SCALAR="SCALAR",Pe.OBJECT="OBJECT",Pe.FIELD_DEFINITION="FIELD_DEFINITION",Pe.ARGUMENT_DEFINITION="ARGUMENT_DEFINITION",Pe.INTERFACE="INTERFACE",Pe.UNION="UNION",Pe.ENUM="ENUM",Pe.ENUM_VALUE="ENUM_VALUE",Pe.INPUT_OBJECT="INPUT_OBJECT",Pe.INPUT_FIELD_DEFINITION="INPUT_FIELD_DEFINITION",g(Ie,"isWhiteSpace$2"),g(De,"isDigit$1"),g(Le,"isLetter$1"),g(Ae,"isNameStart"),g(Me,"isNameContinue"),g(Re,"printBlockString"),g(Fe,"printString");const je=/[\x00-\x1f\x22\x5c\x7f-\x9f]/g;function Ve(e){return Ue[e.charCodeAt(0)]}g(Ve,"escapedReplacer");const Ue=["\\u0000","\\u0001","\\u0002","\\u0003","\\u0004","\\u0005","\\u0006","\\u0007","\\b","\\t","\\n","\\u000B","\\f","\\r","\\u000E","\\u000F","\\u0010","\\u0011","\\u0012","\\u0013","\\u0014","\\u0015","\\u0016","\\u0017","\\u0018","\\u0019","\\u001A","\\u001B","\\u001C","\\u001D","\\u001E","\\u001F","","",'\\"',"","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","\\\\","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","\\u007F","\\u0080","\\u0081","\\u0082","\\u0083","\\u0084","\\u0085","\\u0086","\\u0087","\\u0088","\\u0089","\\u008A","\\u008B","\\u008C","\\u008D","\\u008E","\\u008F","\\u0090","\\u0091","\\u0092","\\u0093","\\u0094","\\u0095","\\u0096","\\u0097","\\u0098","\\u0099","\\u009A","\\u009B","\\u009C","\\u009D","\\u009E","\\u009F"];function Be(e,t){if(!Boolean(e))throw new Error(t)}g(Be,"devAssert");const $e={Name:[],Document:["definitions"],OperationDefinition:["name","variableDefinitions","directives","selectionSet"],VariableDefinition:["variable","type","defaultValue","directives"],Variable:["name"],SelectionSet:["selections"],Field:["alias","name","arguments","directives","selectionSet"],Argument:["name","value"],FragmentSpread:["name","directives"],InlineFragment:["typeCondition","directives","selectionSet"],FragmentDefinition:["name","variableDefinitions","typeCondition","directives","selectionSet"],IntValue:[],FloatValue:[],StringValue:[],BooleanValue:[],NullValue:[],EnumValue:[],ListValue:["values"],ObjectValue:["fields"],ObjectField:["name","value"],Directive:["name","arguments"],NamedType:["name"],ListType:["type"],NonNullType:["type"],SchemaDefinition:["description","directives","operationTypes"],OperationTypeDefinition:["type"],ScalarTypeDefinition:["description","name","directives"],ObjectTypeDefinition:["description","name","interfaces","directives","fields"],FieldDefinition:["description","name","arguments","type","directives"],InputValueDefinition:["description","name","type","defaultValue","directives"],InterfaceTypeDefinition:["description","name","interfaces","directives","fields"],UnionTypeDefinition:["description","name","directives","types"],EnumTypeDefinition:["description","name","directives","values"],EnumValueDefinition:["description","name","directives"],InputObjectTypeDefinition:["description","name","directives","fields"],DirectiveDefinition:["description","name","arguments","locations"],SchemaExtension:["directives","operationTypes"],ScalarTypeExtension:["name","directives"],ObjectTypeExtension:["name","interfaces","directives","fields"],InterfaceTypeExtension:["name","interfaces","directives","fields"],UnionTypeExtension:["name","directives","types"],EnumTypeExtension:["name","directives","values"],InputObjectTypeExtension:["name","directives","fields"]},qe=new Set(Object.keys($e));function He(e){const t=null==e?void 0:e.kind;return"string"==typeof t&&qe.has(t)}let Ge,ze;var We,Ke;g(He,"isNode"),(Ke=Ge||(Ge={})).QUERY="query",Ke.MUTATION="mutation",Ke.SUBSCRIPTION="subscription",(We=ze||(ze={})).NAME="Name",We.DOCUMENT="Document",We.OPERATION_DEFINITION="OperationDefinition",We.VARIABLE_DEFINITION="VariableDefinition",We.SELECTION_SET="SelectionSet",We.FIELD="Field",We.ARGUMENT="Argument",We.FRAGMENT_SPREAD="FragmentSpread",We.INLINE_FRAGMENT="InlineFragment",We.FRAGMENT_DEFINITION="FragmentDefinition",We.VARIABLE="Variable",We.INT="IntValue",We.FLOAT="FloatValue",We.STRING="StringValue",We.BOOLEAN="BooleanValue",We.NULL="NullValue",We.ENUM="EnumValue",We.LIST="ListValue",We.OBJECT="ObjectValue",We.OBJECT_FIELD="ObjectField",We.DIRECTIVE="Directive",We.NAMED_TYPE="NamedType",We.LIST_TYPE="ListType",We.NON_NULL_TYPE="NonNullType",We.SCHEMA_DEFINITION="SchemaDefinition",We.OPERATION_TYPE_DEFINITION="OperationTypeDefinition",We.SCALAR_TYPE_DEFINITION="ScalarTypeDefinition",We.OBJECT_TYPE_DEFINITION="ObjectTypeDefinition",We.FIELD_DEFINITION="FieldDefinition",We.INPUT_VALUE_DEFINITION="InputValueDefinition",We.INTERFACE_TYPE_DEFINITION="InterfaceTypeDefinition",We.UNION_TYPE_DEFINITION="UnionTypeDefinition",We.ENUM_TYPE_DEFINITION="EnumTypeDefinition",We.ENUM_VALUE_DEFINITION="EnumValueDefinition",We.INPUT_OBJECT_TYPE_DEFINITION="InputObjectTypeDefinition",We.DIRECTIVE_DEFINITION="DirectiveDefinition",We.SCHEMA_EXTENSION="SchemaExtension",We.SCALAR_TYPE_EXTENSION="ScalarTypeExtension",We.OBJECT_TYPE_EXTENSION="ObjectTypeExtension",We.INTERFACE_TYPE_EXTENSION="InterfaceTypeExtension",We.UNION_TYPE_EXTENSION="UnionTypeExtension",We.ENUM_TYPE_EXTENSION="EnumTypeExtension",We.INPUT_OBJECT_TYPE_EXTENSION="InputObjectTypeExtension";const Qe=Object.freeze({});function Xe(e,t){let n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:$e;const r=new Map;for(const e of Object.values(ze))r.set(e,Ye(t,e));let i,o,a,s=Array.isArray(e),l=[e],u=-1,c=[],d=e;const f=[],p=[];do{u++;const e=u===l.length,v=e&&0!==c.length;if(e){if(o=0===p.length?void 0:f[f.length-1],d=a,a=p.pop(),v)if(s){d=d.slice();let e=0;for(const[t,n]of c){const r=t-e;null===n?(d.splice(r,1),e++):d[r]=n}}else{d=Object.defineProperties({},Object.getOwnPropertyDescriptors(d));for(const[e,t]of c)d[e]=t}u=i.index,l=i.keys,c=i.edits,s=i.inArray,i=i.prev}else if(a){if(o=s?u:l[u],d=a[o],null==d)continue;f.push(o)}let y;if(!Array.isArray(d)){var h,m;He(d)||Be(!1,`Invalid AST Node: ${Te(d)}.`);const n=e?null===(h=r.get(d.kind))||void 0===h?void 0:h.leave:null===(m=r.get(d.kind))||void 0===m?void 0:m.enter;if(y=null==n?void 0:n.call(t,d,o,a,f,p),y===Qe)break;if(!1===y){if(!e){f.pop();continue}}else if(void 0!==y&&(c.push([o,y]),!e)){if(!He(y)){f.pop();continue}d=y}}var g;void 0===y&&v&&c.push([o,d]),e?f.pop():(i={inArray:s,index:u,keys:l,edits:c,prev:i},s=Array.isArray(d),l=s?d:null!==(g=n[d.kind])&&void 0!==g?g:[],u=-1,c=[],a&&p.push(a),a=d)}while(void 0!==i);return 0!==c.length?c[c.length-1][1]:e}function Ye(e,t){const n=e[t];return"object"==typeof n?n:"function"==typeof n?{enter:n,leave:void 0}:{enter:e.enter,leave:e.leave}}function Je(e){return Xe(e,Ze)}g(Xe,"visit"),g(Ye,"getEnterLeaveForKind"),g(Je,"print");const Ze={Name:{leave:e=>e.value},Variable:{leave:e=>"$"+e.name},Document:{leave:e=>et(e.definitions,"\n\n")},OperationDefinition:{leave(e){const t=nt("(",et(e.variableDefinitions,", "),")"),n=et([e.operation,et([e.name,t]),et(e.directives," ")]," ");return("query"===n?"":n+" ")+e.selectionSet}},VariableDefinition:{leave:e=>{let{variable:t,type:n,defaultValue:r,directives:i}=e;return t+": "+n+nt(" = ",r)+nt(" ",et(i," "))}},SelectionSet:{leave:e=>{let{selections:t}=e;return tt(t)}},Field:{leave(e){let{alias:t,name:n,arguments:r,directives:i,selectionSet:o}=e;const a=nt("",t,": ")+n;let s=a+nt("(",et(r,", "),")");return s.length>80&&(s=a+nt("(\n",rt(et(r,"\n")),"\n)")),et([s,et(i," "),o]," ")}},Argument:{leave:e=>{let{name:t,value:n}=e;return t+": "+n}},FragmentSpread:{leave:e=>{let{name:t,directives:n}=e;return"..."+t+nt(" ",et(n," "))}},InlineFragment:{leave:e=>{let{typeCondition:t,directives:n,selectionSet:r}=e;return et(["...",nt("on ",t),et(n," "),r]," ")}},FragmentDefinition:{leave:e=>{let{name:t,typeCondition:n,variableDefinitions:r,directives:i,selectionSet:o}=e;return`fragment ${t}${nt("(",et(r,", "),")")} on ${n} ${nt("",et(i," ")," ")}`+o}},IntValue:{leave:e=>{let{value:t}=e;return t}},FloatValue:{leave:e=>{let{value:t}=e;return t}},StringValue:{leave:e=>{let{value:t,block:n}=e;return n?Re(t):Fe(t)}},BooleanValue:{leave:e=>{let{value:t}=e;return t?"true":"false"}},NullValue:{leave:()=>"null"},EnumValue:{leave:e=>{let{value:t}=e;return t}},ListValue:{leave:e=>{let{values:t}=e;return"["+et(t,", ")+"]"}},ObjectValue:{leave:e=>{let{fields:t}=e;return"{"+et(t,", ")+"}"}},ObjectField:{leave:e=>{let{name:t,value:n}=e;return t+": "+n}},Directive:{leave:e=>{let{name:t,arguments:n}=e;return"@"+t+nt("(",et(n,", "),")")}},NamedType:{leave:e=>{let{name:t}=e;return t}},ListType:{leave:e=>{let{type:t}=e;return"["+t+"]"}},NonNullType:{leave:e=>{let{type:t}=e;return t+"!"}},SchemaDefinition:{leave:e=>{let{description:t,directives:n,operationTypes:r}=e;return nt("",t,"\n")+et(["schema",et(n," "),tt(r)]," ")}},OperationTypeDefinition:{leave:e=>{let{operation:t,type:n}=e;return t+": "+n}},ScalarTypeDefinition:{leave:e=>{let{description:t,name:n,directives:r}=e;return nt("",t,"\n")+et(["scalar",n,et(r," ")]," ")}},ObjectTypeDefinition:{leave:e=>{let{description:t,name:n,interfaces:r,directives:i,fields:o}=e;return nt("",t,"\n")+et(["type",n,nt("implements ",et(r," & ")),et(i," "),tt(o)]," ")}},FieldDefinition:{leave:e=>{let{description:t,name:n,arguments:r,type:i,directives:o}=e;return nt("",t,"\n")+n+(it(r)?nt("(\n",rt(et(r,"\n")),"\n)"):nt("(",et(r,", "),")"))+": "+i+nt(" ",et(o," "))}},InputValueDefinition:{leave:e=>{let{description:t,name:n,type:r,defaultValue:i,directives:o}=e;return nt("",t,"\n")+et([n+": "+r,nt("= ",i),et(o," ")]," ")}},InterfaceTypeDefinition:{leave:e=>{let{description:t,name:n,interfaces:r,directives:i,fields:o}=e;return nt("",t,"\n")+et(["interface",n,nt("implements ",et(r," & ")),et(i," "),tt(o)]," ")}},UnionTypeDefinition:{leave:e=>{let{description:t,name:n,directives:r,types:i}=e;return nt("",t,"\n")+et(["union",n,et(r," "),nt("= ",et(i," | "))]," ")}},EnumTypeDefinition:{leave:e=>{let{description:t,name:n,directives:r,values:i}=e;return nt("",t,"\n")+et(["enum",n,et(r," "),tt(i)]," ")}},EnumValueDefinition:{leave:e=>{let{description:t,name:n,directives:r}=e;return nt("",t,"\n")+et([n,et(r," ")]," ")}},InputObjectTypeDefinition:{leave:e=>{let{description:t,name:n,directives:r,fields:i}=e;return nt("",t,"\n")+et(["input",n,et(r," "),tt(i)]," ")}},DirectiveDefinition:{leave:e=>{let{description:t,name:n,arguments:r,repeatable:i,locations:o}=e;return nt("",t,"\n")+"directive @"+n+(it(r)?nt("(\n",rt(et(r,"\n")),"\n)"):nt("(",et(r,", "),")"))+(i?" repeatable":"")+" on "+et(o," | ")}},SchemaExtension:{leave:e=>{let{directives:t,operationTypes:n}=e;return et(["extend schema",et(t," "),tt(n)]," ")}},ScalarTypeExtension:{leave:e=>{let{name:t,directives:n}=e;return et(["extend scalar",t,et(n," ")]," ")}},ObjectTypeExtension:{leave:e=>{let{name:t,interfaces:n,directives:r,fields:i}=e;return et(["extend type",t,nt("implements ",et(n," & ")),et(r," "),tt(i)]," ")}},InterfaceTypeExtension:{leave:e=>{let{name:t,interfaces:n,directives:r,fields:i}=e;return et(["extend interface",t,nt("implements ",et(n," & ")),et(r," "),tt(i)]," ")}},UnionTypeExtension:{leave:e=>{let{name:t,directives:n,types:r}=e;return et(["extend union",t,et(n," "),nt("= ",et(r," | "))]," ")}},EnumTypeExtension:{leave:e=>{let{name:t,directives:n,values:r}=e;return et(["extend enum",t,et(n," "),tt(r)]," ")}},InputObjectTypeExtension:{leave:e=>{let{name:t,directives:n,fields:r}=e;return et(["extend input",t,et(n," "),tt(r)]," ")}}};function et(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";var n;return null!==(n=null==e?void 0:e.filter((e=>e)).join(t))&&void 0!==n?n:""}function tt(e){return nt("{\n",rt(et(e,"\n")),"\n}")}function nt(e,t){return null!=t&&""!==t?e+t+(arguments.length>2&&void 0!==arguments[2]?arguments[2]:""):""}function rt(e){return nt(" ",e.replace(/\n/g,"\n "))}function it(e){var t;return null!==(t=null==e?void 0:e.some((e=>e.includes("\n"))))&&void 0!==t&&t}function ot(e){return"object"==typeof e&&"function"==typeof(null==e?void 0:e[Symbol.iterator])}function at(e){return"object"==typeof e&&null!==e}g(et,"join"),g(tt,"block$2"),g(nt,"wrap"),g(rt,"indent"),g(it,"hasMultilineItems"),g(ot,"isIterableObject"),g(at,"isObjectLike");const st=5;function lt(e,t){const[n,r]=t?[e,t]:[void 0,e];let i=" Did you mean ";n&&(i+=n+" ");const o=r.map((e=>`"${e}"`));switch(o.length){case 0:return"";case 1:return i+o[0]+"?";case 2:return i+o[0]+" or "+o[1]+"?"}const a=o.slice(0,st),s=a.pop();return i+a.join(", ")+", or "+s+"?"}function ut(e){return e}g(lt,"didYouMean"),g(ut,"identityFunc");const ct=g((function(e,t){return e instanceof t}),"instanceOf");function dt(e,t){const n=Object.create(null);for(const r of e)n[t(r)]=r;return n}function ft(e,t,n){const r=Object.create(null);for(const i of e)r[t(i)]=n(i);return r}function pt(e,t){const n=Object.create(null);for(const r of Object.keys(e))n[r]=t(e[r],r);return n}function ht(e,t){let n=0,r=0;for(;n0);let s=0;do{++r,s=10*s+o-mt,o=t.charCodeAt(r)}while(vt(o)&&s>0);if(as)return 1}else{if(io)return 1;++n,++r}}return e.length-t.length}g(dt,"keyMap"),g(ft,"keyValMap"),g(pt,"mapValue"),g(ht,"naturalCompare");const mt=48,gt=57;function vt(e){return!isNaN(e)&&mt<=e&&e<=gt}function yt(e,t){const n=Object.create(null),r=new bt(e),i=Math.floor(.4*e.length)+1;for(const e of t){const t=r.measure(e,i);void 0!==t&&(n[e]=t)}return Object.keys(n).sort(((e,t)=>{const r=n[e]-n[t];return 0!==r?r:ht(e,t)}))}g(vt,"isDigit"),g(yt,"suggestionList");class bt{constructor(e){this._input=e,this._inputLowerCase=e.toLowerCase(),this._inputArray=Et(this._inputLowerCase),this._rows=[new Array(e.length+1).fill(0),new Array(e.length+1).fill(0),new Array(e.length+1).fill(0)]}measure(e,t){if(this._input===e)return 0;const n=e.toLowerCase();if(this._inputLowerCase===n)return 1;let r=Et(n),i=this._inputArray;if(r.lengtht)return;const s=this._rows;for(let e=0;e<=a;e++)s[0][e]=e;for(let e=1;e<=o;e++){const n=s[(e-1)%3],o=s[e%3];let l=o[0]=e;for(let t=1;t<=a;t++){const a=r[e-1]===i[t-1]?0:1;let u=Math.min(n[t]+1,o[t-1]+1,n[t-1]+a);if(e>1&&t>1&&r[e-1]===i[t-2]&&r[e-2]===i[t-1]){const n=s[(e-2)%3][t-2];u=Math.min(u,n+1)}ut)return}const l=s[o%3][a];return l<=t?l:void 0}}function Et(e){const t=e.length,n=new Array(t);for(let r=0;r=t)break;n=i.index+i[0].length,r+=1}return{line:r,column:t+1-n}}function St(e){return xt(e.source,Ct(e.source,e.start))}function xt(e,t){const n=e.locationOffset.column-1,r="".padStart(n)+e.body,i=t.line-1,o=e.locationOffset.line-1,a=t.line+o,s=1===t.line?n:0,l=t.column+s,u=`${e.name}:${a}:${l}\n`,c=r.split(/\r\n|[\n\r]/g),d=c[i];if(d.length>120){const e=Math.floor(l/80),t=l%80,n=[];for(let e=0;e["|",e])),["|","^".padStart(t)],["|",n[e+1]]])}return u+kt([[a-1+" |",c[i-1]],[`${a} |`,d],["|","^".padStart(l)],[`${a+1} |`,c[i+1]]])}function kt(e){const t=e.filter((e=>{let[t,n]=e;return void 0!==n})),n=Math.max(...t.map((e=>{let[t]=e;return t.length})));return t.map((e=>{let[t,r]=e;return t.padStart(n)+(r?" "+r:"")})).join("\n")}function Nt(e){const t=e[0];return null==t||"kind"in t||"length"in t?{nodes:t,source:e[1],positions:e[2],path:e[3],originalError:e[4],extensions:e[5]}:t}g(Ct,"getLocation"),g(St,"printLocation"),g(xt,"printSourceLocation"),g(kt,"printPrefixedLines"),g(Nt,"toNormalizedOptions");class _t extends Error{constructor(e){for(var t,n,r,i=arguments.length,o=new Array(i>1?i-1:0),a=1;ae.loc)).filter((e=>null!=e)));this.source=null!=l?l:null==p||null===(n=p[0])||void 0===n?void 0:n.source,this.positions=null!=u?u:null==p?void 0:p.map((e=>e.start)),this.locations=u&&l?u.map((e=>Ct(l,e))):null==p?void 0:p.map((e=>Ct(e.source,e.start)));const h=at(null==d?void 0:d.extensions)?null==d?void 0:d.extensions:void 0;this.extensions=null!==(r=null!=f?f:h)&&void 0!==r?r:Object.create(null),Object.defineProperties(this,{message:{writable:!0,enumerable:!0},name:{enumerable:!1},nodes:{enumerable:!1},source:{enumerable:!1},positions:{enumerable:!1},originalError:{enumerable:!1}}),null!=d&&d.stack?Object.defineProperty(this,"stack",{value:d.stack,writable:!0,configurable:!0}):Error.captureStackTrace?Error.captureStackTrace(this,_t):Object.defineProperty(this,"stack",{value:Error().stack,writable:!0,configurable:!0})}get[Symbol.toStringTag](){return"GraphQLError"}toString(){let e=this.message;if(this.nodes)for(const t of this.nodes)t.loc&&(e+="\n\n"+St(t.loc));else if(this.source&&this.locations)for(const t of this.locations)e+="\n\n"+xt(this.source,t);return e}toJSON(){const e={message:this.message};return null!=this.locations&&(e.locations=this.locations),null!=this.path&&(e.path=this.path),null!=this.extensions&&Object.keys(this.extensions).length>0&&(e.extensions=this.extensions),e}}function Ot(e){return void 0===e||0===e.length?void 0:e}function It(e,t){switch(e.kind){case ze.NULL:return null;case ze.INT:return parseInt(e.value,10);case ze.FLOAT:return parseFloat(e.value);case ze.STRING:case ze.ENUM:case ze.BOOLEAN:return e.value;case ze.LIST:return e.values.map((e=>It(e,t)));case ze.OBJECT:return ft(e.fields,(e=>e.name.value),(e=>It(e.value,t)));case ze.VARIABLE:return null==t?void 0:t[e.name.value]}}function Dt(e){if(null!=e||Be(!1,"Must provide name."),"string"==typeof e||Be(!1,"Expected name to be a string."),0===e.length)throw new _t("Expected name to be a non-empty string.");for(let t=1;to(It(e,t)),this.extensions=Tt(e.extensions),this.astNode=e.astNode,this.extensionASTNodes=null!==(i=e.extensionASTNodes)&&void 0!==i?i:[],null==e.specifiedByURL||"string"==typeof e.specifiedByURL||Be(!1,`${this.name} must provide "specifiedByURL" as a string, but got: ${Te(e.specifiedByURL)}.`),null==e.serialize||"function"==typeof e.serialize||Be(!1,`${this.name} must provide "serialize" function. If this custom Scalar is also used as an input type, ensure "parseValue" and "parseLiteral" functions are also provided.`),e.parseLiteral&&("function"==typeof e.parseValue&&"function"==typeof e.parseLiteral||Be(!1,`${this.name} must provide both "parseValue" and "parseLiteral" functions.`))}get[Symbol.toStringTag](){return"GraphQLScalarType"}toConfig(){return{name:this.name,description:this.description,specifiedByURL:this.specifiedByURL,serialize:this.serialize,parseValue:this.parseValue,parseLiteral:this.parseLiteral,extensions:this.extensions,astNode:this.astNode,extensionASTNodes:this.extensionASTNodes}}toString(){return this.name}toJSON(){return this.toString()}}g(Qt,"GraphQLScalarType");class Xt{constructor(e){var t;this.name=Dt(e.name),this.description=e.description,this.isTypeOf=e.isTypeOf,this.extensions=Tt(e.extensions),this.astNode=e.astNode,this.extensionASTNodes=null!==(t=e.extensionASTNodes)&&void 0!==t?t:[],this._fields=()=>Jt(e),this._interfaces=()=>Yt(e),null==e.isTypeOf||"function"==typeof e.isTypeOf||Be(!1,`${this.name} must provide "isTypeOf" as a function, but got: ${Te(e.isTypeOf)}.`)}get[Symbol.toStringTag](){return"GraphQLObjectType"}getFields(){return"function"==typeof this._fields&&(this._fields=this._fields()),this._fields}getInterfaces(){return"function"==typeof this._interfaces&&(this._interfaces=this._interfaces()),this._interfaces}toConfig(){return{name:this.name,description:this.description,interfaces:this.getInterfaces(),fields:tn(this.getFields()),isTypeOf:this.isTypeOf,extensions:this.extensions,astNode:this.astNode,extensionASTNodes:this.extensionASTNodes}}toString(){return this.name}toJSON(){return this.toString()}}function Yt(e){var t;const n=Wt(null!==(t=e.interfaces)&&void 0!==t?t:[]);return Array.isArray(n)||Be(!1,`${e.name} interfaces must be an Array or a function which returns an Array.`),n}function Jt(e){const t=Kt(e.fields);return en(t)||Be(!1,`${e.name} fields must be an object with field names as keys or a function which returns such an object.`),pt(t,((t,n)=>{var r;en(t)||Be(!1,`${e.name}.${n} field config must be an object.`),null==t.resolve||"function"==typeof t.resolve||Be(!1,`${e.name}.${n} field resolver must be a function if provided, but got: ${Te(t.resolve)}.`);const i=null!==(r=t.args)&&void 0!==r?r:{};return en(i)||Be(!1,`${e.name}.${n} args must be an object with argument names as keys.`),{name:Dt(n),description:t.description,type:t.type,args:Zt(i),resolve:t.resolve,subscribe:t.subscribe,deprecationReason:t.deprecationReason,extensions:Tt(t.extensions),astNode:t.astNode}}))}function Zt(e){return Object.entries(e).map((e=>{let[t,n]=e;return{name:Dt(t),description:n.description,type:n.type,defaultValue:n.defaultValue,deprecationReason:n.deprecationReason,extensions:Tt(n.extensions),astNode:n.astNode}}))}function en(e){return at(e)&&!Array.isArray(e)}function tn(e){return pt(e,(e=>({description:e.description,type:e.type,args:nn(e.args),resolve:e.resolve,subscribe:e.subscribe,deprecationReason:e.deprecationReason,extensions:e.extensions,astNode:e.astNode})))}function nn(e){return ft(e,(e=>e.name),(e=>({description:e.description,type:e.type,defaultValue:e.defaultValue,deprecationReason:e.deprecationReason,extensions:e.extensions,astNode:e.astNode})))}g(Xt,"GraphQLObjectType"),g(Yt,"defineInterfaces"),g(Jt,"defineFieldMap"),g(Zt,"defineArguments"),g(en,"isPlainObj"),g(tn,"fieldsToFieldsConfig"),g(nn,"argsToArgsConfig");class rn{constructor(e){var t;this.name=Dt(e.name),this.description=e.description,this.resolveType=e.resolveType,this.extensions=Tt(e.extensions),this.astNode=e.astNode,this.extensionASTNodes=null!==(t=e.extensionASTNodes)&&void 0!==t?t:[],this._fields=Jt.bind(void 0,e),this._interfaces=Yt.bind(void 0,e),null==e.resolveType||"function"==typeof e.resolveType||Be(!1,`${this.name} must provide "resolveType" as a function, but got: ${Te(e.resolveType)}.`)}get[Symbol.toStringTag](){return"GraphQLInterfaceType"}getFields(){return"function"==typeof this._fields&&(this._fields=this._fields()),this._fields}getInterfaces(){return"function"==typeof this._interfaces&&(this._interfaces=this._interfaces()),this._interfaces}toConfig(){return{name:this.name,description:this.description,interfaces:this.getInterfaces(),fields:tn(this.getFields()),resolveType:this.resolveType,extensions:this.extensions,astNode:this.astNode,extensionASTNodes:this.extensionASTNodes}}toString(){return this.name}toJSON(){return this.toString()}}g(rn,"GraphQLInterfaceType");class on{constructor(e){var t;this.name=Dt(e.name),this.description=e.description,this.resolveType=e.resolveType,this.extensions=Tt(e.extensions),this.astNode=e.astNode,this.extensionASTNodes=null!==(t=e.extensionASTNodes)&&void 0!==t?t:[],this._types=an.bind(void 0,e),null==e.resolveType||"function"==typeof e.resolveType||Be(!1,`${this.name} must provide "resolveType" as a function, but got: ${Te(e.resolveType)}.`)}get[Symbol.toStringTag](){return"GraphQLUnionType"}getTypes(){return"function"==typeof this._types&&(this._types=this._types()),this._types}toConfig(){return{name:this.name,description:this.description,types:this.getTypes(),resolveType:this.resolveType,extensions:this.extensions,astNode:this.astNode,extensionASTNodes:this.extensionASTNodes}}toString(){return this.name}toJSON(){return this.toString()}}function an(e){const t=Wt(e.types);return Array.isArray(t)||Be(!1,`Must provide Array of types or a function which returns such an array for Union ${e.name}.`),t}g(on,"GraphQLUnionType"),g(an,"defineTypes");class sn{constructor(e){var t;this.name=Dt(e.name),this.description=e.description,this.extensions=Tt(e.extensions),this.astNode=e.astNode,this.extensionASTNodes=null!==(t=e.extensionASTNodes)&&void 0!==t?t:[],this._values=un(this.name,e.values),this._valueLookup=new Map(this._values.map((e=>[e.value,e]))),this._nameLookup=dt(this._values,(e=>e.name))}get[Symbol.toStringTag](){return"GraphQLEnumType"}getValues(){return this._values}getValue(e){return this._nameLookup[e]}serialize(e){const t=this._valueLookup.get(e);if(void 0===t)throw new _t(`Enum "${this.name}" cannot represent value: ${Te(e)}`);return t.name}parseValue(e){if("string"!=typeof e){const t=Te(e);throw new _t(`Enum "${this.name}" cannot represent non-string value: ${t}.`+ln(this,t))}const t=this.getValue(e);if(null==t)throw new _t(`Value "${e}" does not exist in "${this.name}" enum.`+ln(this,e));return t.value}parseLiteral(e,t){if(e.kind!==ze.ENUM){const t=Je(e);throw new _t(`Enum "${this.name}" cannot represent non-enum value: ${t}.`+ln(this,t),{nodes:e})}const n=this.getValue(e.value);if(null==n){const t=Je(e);throw new _t(`Value "${t}" does not exist in "${this.name}" enum.`+ln(this,t),{nodes:e})}return n.value}toConfig(){const e=ft(this.getValues(),(e=>e.name),(e=>({description:e.description,value:e.value,deprecationReason:e.deprecationReason,extensions:e.extensions,astNode:e.astNode})));return{name:this.name,description:this.description,values:e,extensions:this.extensions,astNode:this.astNode,extensionASTNodes:this.extensionASTNodes}}toString(){return this.name}toJSON(){return this.toString()}}function ln(e,t){return lt("the enum value",yt(t,e.getValues().map((e=>e.name))))}function un(e,t){return en(t)||Be(!1,`${e} values must be an object with value names as keys.`),Object.entries(t).map((t=>{let[n,r]=t;return en(r)||Be(!1,`${e}.${n} must refer to an object with a "value" key representing an internal value but got: ${Te(r)}.`),{name:Lt(n),description:r.description,value:void 0!==r.value?r.value:n,deprecationReason:r.deprecationReason,extensions:Tt(r.extensions),astNode:r.astNode}}))}g(sn,"GraphQLEnumType"),g(ln,"didYouMeanEnumValue"),g(un,"defineEnumValues");class cn{constructor(e){var t;this.name=Dt(e.name),this.description=e.description,this.extensions=Tt(e.extensions),this.astNode=e.astNode,this.extensionASTNodes=null!==(t=e.extensionASTNodes)&&void 0!==t?t:[],this._fields=dn.bind(void 0,e)}get[Symbol.toStringTag](){return"GraphQLInputObjectType"}getFields(){return"function"==typeof this._fields&&(this._fields=this._fields()),this._fields}toConfig(){const e=pt(this.getFields(),(e=>({description:e.description,type:e.type,defaultValue:e.defaultValue,deprecationReason:e.deprecationReason,extensions:e.extensions,astNode:e.astNode})));return{name:this.name,description:this.description,fields:e,extensions:this.extensions,astNode:this.astNode,extensionASTNodes:this.extensionASTNodes}}toString(){return this.name}toJSON(){return this.toString()}}function dn(e){const t=Kt(e.fields);return en(t)||Be(!1,`${e.name} fields must be an object with field names as keys or a function which returns such an object.`),pt(t,((t,n)=>(!("resolve"in t)||Be(!1,`${e.name}.${n} field has a resolve property, but Input Types cannot define resolvers.`),{name:Dt(n),description:t.description,type:t.type,defaultValue:t.defaultValue,deprecationReason:t.deprecationReason,extensions:Tt(t.extensions),astNode:t.astNode})))}g(cn,"GraphQLInputObjectType"),g(dn,"defineInputFieldMap");const fn=2147483647,pn=-2147483648,hn=new Qt({name:"Int",description:"The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.",serialize(e){const t=bn(e);if("boolean"==typeof t)return t?1:0;let n=t;if("string"==typeof t&&""!==t&&(n=Number(t)),"number"!=typeof n||!Number.isInteger(n))throw new _t(`Int cannot represent non-integer value: ${Te(t)}`);if(n>fn||nfn||efn||t({description:{type:gn,resolve:e=>e.description},types:{description:"A list of all types supported by this server.",type:new Gt(new Ht(new Gt(xn))),resolve(e){return Object.values(e.getTypeMap())}},queryType:{description:"The type that query operations will be rooted at.",type:new Gt(xn),resolve:e=>e.getQueryType()},mutationType:{description:"If this server supports mutation, the type that mutation operations will be rooted at.",type:xn,resolve:e=>e.getMutationType()},subscriptionType:{description:"If this server support subscription, the type that subscription operations will be rooted at.",type:xn,resolve:e=>e.getSubscriptionType()},directives:{description:"A list of all directives supported by this server.",type:new Gt(new Ht(new Gt(Cn))),resolve:e=>e.getDirectives()}})}),Cn=new Xt({name:"__Directive",description:"A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.\n\nIn some cases, you need to provide options to alter GraphQL's execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor.",fields:()=>({name:{type:new Gt(gn),resolve:e=>e.name},description:{type:gn,resolve:e=>e.description},isRepeatable:{type:new Gt(vn),resolve:e=>e.isRepeatable},locations:{type:new Gt(new Ht(new Gt(Sn))),resolve:e=>e.locations},args:{type:new Gt(new Ht(new Gt(Nn))),args:{includeDeprecated:{type:vn,defaultValue:!1}},resolve(e,t){let{includeDeprecated:n}=t;return n?e.args:e.args.filter((e=>null==e.deprecationReason))}}})}),Sn=new sn({name:"__DirectiveLocation",description:"A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies.",values:{QUERY:{value:Oe.QUERY,description:"Location adjacent to a query operation."},MUTATION:{value:Oe.MUTATION,description:"Location adjacent to a mutation operation."},SUBSCRIPTION:{value:Oe.SUBSCRIPTION,description:"Location adjacent to a subscription operation."},FIELD:{value:Oe.FIELD,description:"Location adjacent to a field."},FRAGMENT_DEFINITION:{value:Oe.FRAGMENT_DEFINITION,description:"Location adjacent to a fragment definition."},FRAGMENT_SPREAD:{value:Oe.FRAGMENT_SPREAD,description:"Location adjacent to a fragment spread."},INLINE_FRAGMENT:{value:Oe.INLINE_FRAGMENT,description:"Location adjacent to an inline fragment."},VARIABLE_DEFINITION:{value:Oe.VARIABLE_DEFINITION,description:"Location adjacent to a variable definition."},SCHEMA:{value:Oe.SCHEMA,description:"Location adjacent to a schema definition."},SCALAR:{value:Oe.SCALAR,description:"Location adjacent to a scalar definition."},OBJECT:{value:Oe.OBJECT,description:"Location adjacent to an object type definition."},FIELD_DEFINITION:{value:Oe.FIELD_DEFINITION,description:"Location adjacent to a field definition."},ARGUMENT_DEFINITION:{value:Oe.ARGUMENT_DEFINITION,description:"Location adjacent to an argument definition."},INTERFACE:{value:Oe.INTERFACE,description:"Location adjacent to an interface definition."},UNION:{value:Oe.UNION,description:"Location adjacent to a union definition."},ENUM:{value:Oe.ENUM,description:"Location adjacent to an enum definition."},ENUM_VALUE:{value:Oe.ENUM_VALUE,description:"Location adjacent to an enum value definition."},INPUT_OBJECT:{value:Oe.INPUT_OBJECT,description:"Location adjacent to an input object type definition."},INPUT_FIELD_DEFINITION:{value:Oe.INPUT_FIELD_DEFINITION,description:"Location adjacent to an input object field definition."}}}),xn=new Xt({name:"__Type",description:"The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the `__TypeKind` enum.\n\nDepending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name, description and optional `specifiedByURL`, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose other types.",fields:()=>({kind:{type:new Gt(Dn),resolve(e){return Mt(e)?On.SCALAR:Rt(e)?On.OBJECT:Ft(e)?On.INTERFACE:Pt(e)?On.UNION:jt(e)?On.ENUM:Vt(e)?On.INPUT_OBJECT:Ut(e)?On.LIST:Bt(e)?On.NON_NULL:void _e(!1,`Unexpected type: "${Te(e)}".`)}},name:{type:gn,resolve:e=>"name"in e?e.name:void 0},description:{type:gn,resolve:e=>"description"in e?e.description:void 0},specifiedByURL:{type:gn,resolve:e=>"specifiedByURL"in e?e.specifiedByURL:void 0},fields:{type:new Ht(new Gt(kn)),args:{includeDeprecated:{type:vn,defaultValue:!1}},resolve(e,t){let{includeDeprecated:n}=t;if(Rt(e)||Ft(e)){const t=Object.values(e.getFields());return n?t:t.filter((e=>null==e.deprecationReason))}}},interfaces:{type:new Ht(new Gt(xn)),resolve(e){if(Rt(e)||Ft(e))return e.getInterfaces()}},possibleTypes:{type:new Ht(new Gt(xn)),resolve(e,t,n,r){let{schema:i}=r;if(qt(e))return i.getPossibleTypes(e)}},enumValues:{type:new Ht(new Gt(_n)),args:{includeDeprecated:{type:vn,defaultValue:!1}},resolve(e,t){let{includeDeprecated:n}=t;if(jt(e)){const t=e.getValues();return n?t:t.filter((e=>null==e.deprecationReason))}}},inputFields:{type:new Ht(new Gt(Nn)),args:{includeDeprecated:{type:vn,defaultValue:!1}},resolve(e,t){let{includeDeprecated:n}=t;if(Vt(e)){const t=Object.values(e.getFields());return n?t:t.filter((e=>null==e.deprecationReason))}}},ofType:{type:xn,resolve:e=>"ofType"in e?e.ofType:void 0}})}),kn=new Xt({name:"__Field",description:"Object and Interface types are described by a list of Fields, each of which has a name, potentially a list of arguments, and a return type.",fields:()=>({name:{type:new Gt(gn),resolve:e=>e.name},description:{type:gn,resolve:e=>e.description},args:{type:new Gt(new Ht(new Gt(Nn))),args:{includeDeprecated:{type:vn,defaultValue:!1}},resolve(e,t){let{includeDeprecated:n}=t;return n?e.args:e.args.filter((e=>null==e.deprecationReason))}},type:{type:new Gt(xn),resolve:e=>e.type},isDeprecated:{type:new Gt(vn),resolve:e=>null!=e.deprecationReason},deprecationReason:{type:gn,resolve:e=>e.deprecationReason}})}),Nn=new Xt({name:"__InputValue",description:"Arguments provided to Fields or Directives and the input fields of an InputObject are represented as Input Values which describe their type and optionally a default value.",fields:()=>({name:{type:new Gt(gn),resolve:e=>e.name},description:{type:gn,resolve:e=>e.description},type:{type:new Gt(xn),resolve:e=>e.type},defaultValue:{type:gn,description:"A GraphQL-formatted string representing the default value for this input value.",resolve(e){const{type:t,defaultValue:n}=e,r=En(n,t);return r?Je(r):null}},isDeprecated:{type:new Gt(vn),resolve:e=>null!=e.deprecationReason},deprecationReason:{type:gn,resolve:e=>e.deprecationReason}})}),_n=new Xt({name:"__EnumValue",description:"One possible value for a given Enum. Enum values are unique values, not a placeholder for a string or numeric value. However an Enum value is returned in a JSON response as a string.",fields:()=>({name:{type:new Gt(gn),resolve:e=>e.name},description:{type:gn,resolve:e=>e.description},isDeprecated:{type:new Gt(vn),resolve:e=>null!=e.deprecationReason},deprecationReason:{type:gn,resolve:e=>e.deprecationReason}})});let On;var In;(In=On||(On={})).SCALAR="SCALAR",In.OBJECT="OBJECT",In.INTERFACE="INTERFACE",In.UNION="UNION",In.ENUM="ENUM",In.INPUT_OBJECT="INPUT_OBJECT",In.LIST="LIST",In.NON_NULL="NON_NULL";const Dn=new sn({name:"__TypeKind",description:"An enum describing what kind of type a given `__Type` is.",values:{SCALAR:{value:On.SCALAR,description:"Indicates this type is a scalar."},OBJECT:{value:On.OBJECT,description:"Indicates this type is an object. `fields` and `interfaces` are valid fields."},INTERFACE:{value:On.INTERFACE,description:"Indicates this type is an interface. `fields`, `interfaces`, and `possibleTypes` are valid fields."},UNION:{value:On.UNION,description:"Indicates this type is a union. `possibleTypes` is a valid field."},ENUM:{value:On.ENUM,description:"Indicates this type is an enum. `enumValues` is a valid field."},INPUT_OBJECT:{value:On.INPUT_OBJECT,description:"Indicates this type is an input object. `inputFields` is a valid field."},LIST:{value:On.LIST,description:"Indicates this type is a list. `ofType` is a valid field."},NON_NULL:{value:On.NON_NULL,description:"Indicates this type is a non-null. `ofType` is a valid field."}}}),Ln={name:"__schema",type:new Gt(wn),description:"Access the current type schema of this server.",args:[],resolve:(e,t,n,r)=>{let{schema:i}=r;return i},deprecationReason:void 0,extensions:Object.create(null),astNode:void 0};e.S=Ln;const An={name:"__type",type:xn,description:"Request the type information of a single type.",args:[{name:"name",description:void 0,type:new Gt(gn),defaultValue:void 0,deprecationReason:void 0,extensions:Object.create(null),astNode:void 0}],resolve:(e,t,n,r)=>{let{name:i}=t,{schema:o}=r;return o.getType(i)},deprecationReason:void 0,extensions:Object.create(null),astNode:void 0};e.T=An;const Mn={name:"__typename",type:new Gt(gn),description:"The name of the current Object type at runtime.",args:[],resolve:(e,t,n,r)=>{let{parentType:i}=r;return i.name},deprecationReason:void 0,extensions:Object.create(null),astNode:void 0};function Rn(e){let t;return Pn(e,(e=>{switch(e.kind){case"Query":case"ShortQuery":case"Mutation":case"Subscription":case"FragmentDefinition":t=e}})),t}function Fn(e,t,n){return n===Ln.name&&e.getQueryType()===t?Ln:n===An.name&&e.getQueryType()===t?An:n===Mn.name&&(0,r.isCompositeType)(t)?Mn:"getFields"in t?t.getFields()[n]:null}function Pn(e,t){const n=[];let r=e;for(;null==r?void 0:r.kind;)n.push(r),r=r.prevState;for(let e=n.length-1;e>=0;e--)t(n[e])}function jn(e){const t=Object.keys(e),n=t.length,r=new Array(n);for(let i=0;i({proximity:qn($n(e.label),t),entry:e}))),(e=>e.proximity<=2)),(e=>!e.entry.isDeprecated)).sort(((e,t)=>(e.entry.isDeprecated?1:0)-(t.entry.isDeprecated?1:0)||e.proximity-t.proximity||e.entry.label.length-t.entry.label.length)).map((e=>e.entry)):Bn(e,(e=>!e.isDeprecated))}function Bn(e,t){const n=e.filter(t);return 0===n.length?e:n}function $n(e){return e.toLowerCase().replaceAll(/\W/g,"")}function qn(e,t){let n=Hn(t,e);return e.length>t.length&&(n-=e.length-t.length-1,n+=0===e.indexOf(t)?0:.5),n}function Hn(e,t){let n,r;const i=[],o=e.length,a=t.length;for(n=0;n<=o;n++)i[n]=[n];for(r=1;r<=a;r++)i[0][r]=r;for(n=1;n<=o;n++)for(r=1;r<=a;r++){const o=e[n-1]===t[r-1]?0:1;i[n][r]=Math.min(i[n-1][r]+1,i[n][r-1]+1,i[n-1][r-1]+o),n>1&&r>1&&e[n-1]===t[r-2]&&e[n-2]===t[r-1]&&(i[n][r]=Math.min(i[n][r],i[n-2][r-2]+o))}return i[o][a]}var Gn,zn,Wn,Kn,Qn,Xn,Yn,Jn,Zn,er,tr,nr,rr,ir,or,ar,sr,lr,ur,cr,dr,fr,pr,hr,mr,gr,vr,yr,br,Er,Tr;e.a=Mn,Object.freeze([wn,Cn,Sn,xn,kn,Nn,_n,Dn]),g(Rn,"getDefinitionState"),g(Fn,"getFieldDef"),g(Pn,"forEachState"),g(jn,"objectValues"),g(Vn,"hintList"),g(Un,"filterAndSortList"),g(Bn,"filterNonEmpty"),g($n,"normalizeText"),g(qn,"getProximity"),g(Hn,"lexicalDistance"),function(e){function t(e){return"string"==typeof e}g(t,"is"),e.is=t}(Gn||(Gn={})),function(e){function t(e){return"string"==typeof e}g(t,"is"),e.is=t}(zn||(zn={})),function(e){function t(t){return"number"==typeof t&&e.MIN_VALUE<=t&&t<=e.MAX_VALUE}e.MIN_VALUE=-2147483648,e.MAX_VALUE=2147483647,g(t,"is"),e.is=t}(Wn||(Wn={})),function(e){function t(t){return"number"==typeof t&&e.MIN_VALUE<=t&&t<=e.MAX_VALUE}e.MIN_VALUE=0,e.MAX_VALUE=2147483647,g(t,"is"),e.is=t}(Kn||(Kn={})),function(e){function t(e,t){return e===Number.MAX_VALUE&&(e=Kn.MAX_VALUE),t===Number.MAX_VALUE&&(t=Kn.MAX_VALUE),{line:e,character:t}}function n(e){var t=e;return Si.objectLiteral(t)&&Si.uinteger(t.line)&&Si.uinteger(t.character)}g(t,"create"),e.create=t,g(n,"is"),e.is=n}(Qn||(Qn={})),function(e){function t(e,t,n,r){if(Si.uinteger(e)&&Si.uinteger(t)&&Si.uinteger(n)&&Si.uinteger(r))return{start:Qn.create(e,t),end:Qn.create(n,r)};if(Qn.is(e)&&Qn.is(t))return{start:e,end:t};throw new Error("Range#create called with invalid arguments[".concat(e,", ").concat(t,", ").concat(n,", ").concat(r,"]"))}function n(e){var t=e;return Si.objectLiteral(t)&&Qn.is(t.start)&&Qn.is(t.end)}g(t,"create"),e.create=t,g(n,"is"),e.is=n}(Xn||(Xn={})),function(e){function t(e,t){return{uri:e,range:t}}function n(e){var t=e;return Si.defined(t)&&Xn.is(t.range)&&(Si.string(t.uri)||Si.undefined(t.uri))}g(t,"create"),e.create=t,g(n,"is"),e.is=n}(Yn||(Yn={})),function(e){function t(e,t,n,r){return{targetUri:e,targetRange:t,targetSelectionRange:n,originSelectionRange:r}}function n(e){var t=e;return Si.defined(t)&&Xn.is(t.targetRange)&&Si.string(t.targetUri)&&Xn.is(t.targetSelectionRange)&&(Xn.is(t.originSelectionRange)||Si.undefined(t.originSelectionRange))}g(t,"create"),e.create=t,g(n,"is"),e.is=n}(Jn||(Jn={})),function(e){function t(e,t,n,r){return{red:e,green:t,blue:n,alpha:r}}function n(e){var t=e;return Si.objectLiteral(t)&&Si.numberRange(t.red,0,1)&&Si.numberRange(t.green,0,1)&&Si.numberRange(t.blue,0,1)&&Si.numberRange(t.alpha,0,1)}g(t,"create"),e.create=t,g(n,"is"),e.is=n}(Zn||(Zn={})),function(e){function t(e,t){return{range:e,color:t}}function n(e){var t=e;return Si.objectLiteral(t)&&Xn.is(t.range)&&Zn.is(t.color)}g(t,"create"),e.create=t,g(n,"is"),e.is=n}(er||(er={})),function(e){function t(e,t,n){return{label:e,textEdit:t,additionalTextEdits:n}}function n(e){var t=e;return Si.objectLiteral(t)&&Si.string(t.label)&&(Si.undefined(t.textEdit)||cr.is(t))&&(Si.undefined(t.additionalTextEdits)||Si.typedArray(t.additionalTextEdits,cr.is))}g(t,"create"),e.create=t,g(n,"is"),e.is=n}(tr||(tr={})),(Tr=nr||(nr={})).Comment="comment",Tr.Imports="imports",Tr.Region="region",function(e){function t(e,t,n,r,i,o){var a={startLine:e,endLine:t};return Si.defined(n)&&(a.startCharacter=n),Si.defined(r)&&(a.endCharacter=r),Si.defined(i)&&(a.kind=i),Si.defined(o)&&(a.collapsedText=o),a}function n(e){var t=e;return Si.objectLiteral(t)&&Si.uinteger(t.startLine)&&Si.uinteger(t.startLine)&&(Si.undefined(t.startCharacter)||Si.uinteger(t.startCharacter))&&(Si.undefined(t.endCharacter)||Si.uinteger(t.endCharacter))&&(Si.undefined(t.kind)||Si.string(t.kind))}g(t,"create"),e.create=t,g(n,"is"),e.is=n}(rr||(rr={})),function(e){function t(e,t){return{location:e,message:t}}function n(e){var t=e;return Si.defined(t)&&Yn.is(t.location)&&Si.string(t.message)}g(t,"create"),e.create=t,g(n,"is"),e.is=n}(ir||(ir={})),(Er=or||(or={})).Error=1,Er.Warning=2,Er.Information=3,Er.Hint=4,(br=ar||(ar={})).Unnecessary=1,br.Deprecated=2,function(e){function t(e){var t=e;return Si.objectLiteral(t)&&Si.string(t.href)}g(t,"is"),e.is=t}(sr||(sr={})),function(e){function t(e,t,n,r,i,o){var a={range:e,message:t};return Si.defined(n)&&(a.severity=n),Si.defined(r)&&(a.code=r),Si.defined(i)&&(a.source=i),Si.defined(o)&&(a.relatedInformation=o),a}function n(e){var t,n=e;return Si.defined(n)&&Xn.is(n.range)&&Si.string(n.message)&&(Si.number(n.severity)||Si.undefined(n.severity))&&(Si.integer(n.code)||Si.string(n.code)||Si.undefined(n.code))&&(Si.undefined(n.codeDescription)||Si.string(null===(t=n.codeDescription)||void 0===t?void 0:t.href))&&(Si.string(n.source)||Si.undefined(n.source))&&(Si.undefined(n.relatedInformation)||Si.typedArray(n.relatedInformation,ir.is))}g(t,"create"),e.create=t,g(n,"is"),e.is=n}(lr||(lr={})),function(e){function t(e,t){for(var n=[],r=2;r0&&(i.arguments=n),i}function n(e){var t=e;return Si.defined(t)&&Si.string(t.title)&&Si.string(t.command)}g(t,"create"),e.create=t,g(n,"is"),e.is=n}(ur||(ur={})),function(e){function t(e,t){return{range:e,newText:t}}function n(e,t){return{range:{start:e,end:e},newText:t}}function r(e){return{range:e,newText:""}}function i(e){var t=e;return Si.objectLiteral(t)&&Si.string(t.newText)&&Xn.is(t.range)}g(t,"replace"),e.replace=t,g(n,"insert"),e.insert=n,g(r,"del"),e.del=r,g(i,"is"),e.is=i}(cr||(cr={})),function(e){function t(e,t,n){var r={label:e};return void 0!==t&&(r.needsConfirmation=t),void 0!==n&&(r.description=n),r}function n(e){var t=e;return Si.objectLiteral(t)&&Si.string(t.label)&&(Si.boolean(t.needsConfirmation)||void 0===t.needsConfirmation)&&(Si.string(t.description)||void 0===t.description)}g(t,"create"),e.create=t,g(n,"is"),e.is=n}(dr||(dr={})),function(e){function t(e){var t=e;return Si.string(t)}g(t,"is"),e.is=t}(fr||(fr={})),function(e){function t(e,t,n){return{range:e,newText:t,annotationId:n}}function n(e,t,n){return{range:{start:e,end:e},newText:t,annotationId:n}}function r(e,t){return{range:e,newText:"",annotationId:t}}function i(e){var t=e;return cr.is(t)&&(dr.is(t.annotationId)||fr.is(t.annotationId))}g(t,"replace"),e.replace=t,g(n,"insert"),e.insert=n,g(r,"del"),e.del=r,g(i,"is"),e.is=i}(pr||(pr={})),function(e){function t(e,t){return{textDocument:e,edits:t}}function n(e){var t=e;return Si.defined(t)&&Sr.is(t.textDocument)&&Array.isArray(t.edits)}g(t,"create"),e.create=t,g(n,"is"),e.is=n}(hr||(hr={})),function(e){function t(e,t,n){var r={kind:"create",uri:e};return void 0===t||void 0===t.overwrite&&void 0===t.ignoreIfExists||(r.options=t),void 0!==n&&(r.annotationId=n),r}function n(e){var t=e;return t&&"create"===t.kind&&Si.string(t.uri)&&(void 0===t.options||(void 0===t.options.overwrite||Si.boolean(t.options.overwrite))&&(void 0===t.options.ignoreIfExists||Si.boolean(t.options.ignoreIfExists)))&&(void 0===t.annotationId||fr.is(t.annotationId))}g(t,"create"),e.create=t,g(n,"is"),e.is=n}(mr||(mr={})),function(e){function t(e,t,n,r){var i={kind:"rename",oldUri:e,newUri:t};return void 0===n||void 0===n.overwrite&&void 0===n.ignoreIfExists||(i.options=n),void 0!==r&&(i.annotationId=r),i}function n(e){var t=e;return t&&"rename"===t.kind&&Si.string(t.oldUri)&&Si.string(t.newUri)&&(void 0===t.options||(void 0===t.options.overwrite||Si.boolean(t.options.overwrite))&&(void 0===t.options.ignoreIfExists||Si.boolean(t.options.ignoreIfExists)))&&(void 0===t.annotationId||fr.is(t.annotationId))}g(t,"create"),e.create=t,g(n,"is"),e.is=n}(gr||(gr={})),function(e){function t(e,t,n){var r={kind:"delete",uri:e};return void 0===t||void 0===t.recursive&&void 0===t.ignoreIfNotExists||(r.options=t),void 0!==n&&(r.annotationId=n),r}function n(e){var t=e;return t&&"delete"===t.kind&&Si.string(t.uri)&&(void 0===t.options||(void 0===t.options.recursive||Si.boolean(t.options.recursive))&&(void 0===t.options.ignoreIfNotExists||Si.boolean(t.options.ignoreIfNotExists)))&&(void 0===t.annotationId||fr.is(t.annotationId))}g(t,"create"),e.create=t,g(n,"is"),e.is=n}(vr||(vr={})),function(e){function t(e){var t=e;return t&&(void 0!==t.changes||void 0!==t.documentChanges)&&(void 0===t.documentChanges||t.documentChanges.every((function(e){return Si.string(e.kind)?mr.is(e)||gr.is(e)||vr.is(e):hr.is(e)})))}g(t,"is"),e.is=t}(yr||(yr={}));var wr,Cr,Sr,xr,kr,Nr,_r,Or,Ir,Dr,Lr,Ar,Mr,Rr,Fr,Pr,jr,Vr,Ur,Br,$r,qr,Hr,Gr,zr,Wr,Kr,Qr,Xr,Yr,Jr,Zr,ei,ti,ni,ri,ii,oi,ai,si,li,ui,ci,di,fi,pi,hi,mi,gi,vi,yi,bi,Ei,Ti,wi=function(){function e(e,t){this.edits=e,this.changeAnnotations=t}return g(e,"TextEditChangeImpl"),e.prototype.insert=function(e,t,n){var r,i;if(void 0===n?r=cr.insert(e,t):fr.is(n)?(i=n,r=pr.insert(e,t,n)):(this.assertChangeAnnotations(this.changeAnnotations),i=this.changeAnnotations.manage(n),r=pr.insert(e,t,i)),this.edits.push(r),void 0!==i)return i},e.prototype.replace=function(e,t,n){var r,i;if(void 0===n?r=cr.replace(e,t):fr.is(n)?(i=n,r=pr.replace(e,t,n)):(this.assertChangeAnnotations(this.changeAnnotations),i=this.changeAnnotations.manage(n),r=pr.replace(e,t,i)),this.edits.push(r),void 0!==i)return i},e.prototype.delete=function(e,t){var n,r;if(void 0===t?n=cr.del(e):fr.is(t)?(r=t,n=pr.del(e,t)):(this.assertChangeAnnotations(this.changeAnnotations),r=this.changeAnnotations.manage(t),n=pr.del(e,r)),this.edits.push(n),void 0!==r)return r},e.prototype.add=function(e){this.edits.push(e)},e.prototype.all=function(){return this.edits},e.prototype.clear=function(){this.edits.splice(0,this.edits.length)},e.prototype.assertChangeAnnotations=function(e){if(void 0===e)throw new Error("Text edit change is not configured to manage change annotations.")},e}(),Ci=function(){function e(e){this._annotations=void 0===e?Object.create(null):e,this._counter=0,this._size=0}return g(e,"ChangeAnnotations"),e.prototype.all=function(){return this._annotations},Object.defineProperty(e.prototype,"size",{get:function(){return this._size},enumerable:!1,configurable:!0}),e.prototype.manage=function(e,t){var n;if(fr.is(e)?n=e:(n=this.nextId(),t=e),void 0!==this._annotations[n])throw new Error("Id ".concat(n," is already in use."));if(void 0===t)throw new Error("No annotation provided for id ".concat(n));return this._annotations[n]=t,this._size++,n},e.prototype.nextId=function(){return this._counter++,this._counter.toString()},e}();(function(){function e(e){var t=this;this._textEditChanges=Object.create(null),void 0!==e?(this._workspaceEdit=e,e.documentChanges?(this._changeAnnotations=new Ci(e.changeAnnotations),e.changeAnnotations=this._changeAnnotations.all(),e.documentChanges.forEach((function(e){if(hr.is(e)){var n=new wi(e.edits,t._changeAnnotations);t._textEditChanges[e.textDocument.uri]=n}}))):e.changes&&Object.keys(e.changes).forEach((function(n){var r=new wi(e.changes[n]);t._textEditChanges[n]=r}))):this._workspaceEdit={}}g(e,"WorkspaceChange"),Object.defineProperty(e.prototype,"edit",{get:function(){return this.initDocumentChanges(),void 0!==this._changeAnnotations&&(0===this._changeAnnotations.size?this._workspaceEdit.changeAnnotations=void 0:this._workspaceEdit.changeAnnotations=this._changeAnnotations.all()),this._workspaceEdit},enumerable:!1,configurable:!0}),e.prototype.getTextEditChange=function(e){if(Sr.is(e)){if(this.initDocumentChanges(),void 0===this._workspaceEdit.documentChanges)throw new Error("Workspace edit is not configured for document changes.");var t={uri:e.uri,version:e.version};if(!(r=this._textEditChanges[t.uri])){var n={textDocument:t,edits:i=[]};this._workspaceEdit.documentChanges.push(n),r=new wi(i,this._changeAnnotations),this._textEditChanges[t.uri]=r}return r}if(this.initChanges(),void 0===this._workspaceEdit.changes)throw new Error("Workspace edit is not configured for normal text edit changes.");var r;if(!(r=this._textEditChanges[e])){var i=[];this._workspaceEdit.changes[e]=i,r=new wi(i),this._textEditChanges[e]=r}return r},e.prototype.initDocumentChanges=function(){void 0===this._workspaceEdit.documentChanges&&void 0===this._workspaceEdit.changes&&(this._changeAnnotations=new Ci,this._workspaceEdit.documentChanges=[],this._workspaceEdit.changeAnnotations=this._changeAnnotations.all())},e.prototype.initChanges=function(){void 0===this._workspaceEdit.documentChanges&&void 0===this._workspaceEdit.changes&&(this._workspaceEdit.changes=Object.create(null))},e.prototype.createFile=function(e,t,n){if(this.initDocumentChanges(),void 0===this._workspaceEdit.documentChanges)throw new Error("Workspace edit is not configured for document changes.");var r,i,o;if(dr.is(t)||fr.is(t)?r=t:n=t,void 0===r?i=mr.create(e,n):(o=fr.is(r)?r:this._changeAnnotations.manage(r),i=mr.create(e,n,o)),this._workspaceEdit.documentChanges.push(i),void 0!==o)return o},e.prototype.renameFile=function(e,t,n,r){if(this.initDocumentChanges(),void 0===this._workspaceEdit.documentChanges)throw new Error("Workspace edit is not configured for document changes.");var i,o,a;if(dr.is(n)||fr.is(n)?i=n:r=n,void 0===i?o=gr.create(e,t,r):(a=fr.is(i)?i:this._changeAnnotations.manage(i),o=gr.create(e,t,r,a)),this._workspaceEdit.documentChanges.push(o),void 0!==a)return a},e.prototype.deleteFile=function(e,t,n){if(this.initDocumentChanges(),void 0===this._workspaceEdit.documentChanges)throw new Error("Workspace edit is not configured for document changes.");var r,i,o;if(dr.is(t)||fr.is(t)?r=t:n=t,void 0===r?i=vr.create(e,n):(o=fr.is(r)?r:this._changeAnnotations.manage(r),i=vr.create(e,n,o)),this._workspaceEdit.documentChanges.push(i),void 0!==o)return o}})(),function(e){function t(e){return{uri:e}}function n(e){var t=e;return Si.defined(t)&&Si.string(t.uri)}g(t,"create"),e.create=t,g(n,"is"),e.is=n}(wr||(wr={})),function(e){function t(e,t){return{uri:e,version:t}}function n(e){var t=e;return Si.defined(t)&&Si.string(t.uri)&&Si.integer(t.version)}g(t,"create"),e.create=t,g(n,"is"),e.is=n}(Cr||(Cr={})),function(e){function t(e,t){return{uri:e,version:t}}function n(e){var t=e;return Si.defined(t)&&Si.string(t.uri)&&(null===t.version||Si.integer(t.version))}g(t,"create"),e.create=t,g(n,"is"),e.is=n}(Sr||(Sr={})),function(e){function t(e,t,n,r){return{uri:e,languageId:t,version:n,text:r}}function n(e){var t=e;return Si.defined(t)&&Si.string(t.uri)&&Si.string(t.languageId)&&Si.integer(t.version)&&Si.string(t.text)}g(t,"create"),e.create=t,g(n,"is"),e.is=n}(xr||(xr={})),function(e){function t(t){var n=t;return n===e.PlainText||n===e.Markdown}e.PlainText="plaintext",e.Markdown="markdown",g(t,"is"),e.is=t}(kr||(kr={})),function(e){function t(e){var t=e;return Si.objectLiteral(e)&&kr.is(t.kind)&&Si.string(t.value)}g(t,"is"),e.is=t}(Nr||(Nr={})),(Ti=_r||(_r={})).Text=1,Ti.Method=2,Ti.Function=3,Ti.Constructor=4,Ti.Field=5,Ti.Variable=6,Ti.Class=7,Ti.Interface=8,Ti.Module=9,Ti.Property=10,Ti.Unit=11,Ti.Value=12,Ti.Enum=13,Ti.Keyword=14,Ti.Snippet=15,Ti.Color=16,Ti.File=17,Ti.Reference=18,Ti.Folder=19,Ti.EnumMember=20,Ti.Constant=21,Ti.Struct=22,Ti.Event=23,Ti.Operator=24,Ti.TypeParameter=25,(Ei=Or||(Or={})).PlainText=1,Ei.Snippet=2,(Ir||(Ir={})).Deprecated=1,function(e){function t(e,t,n){return{newText:e,insert:t,replace:n}}function n(e){var t=e;return t&&Si.string(t.newText)&&Xn.is(t.insert)&&Xn.is(t.replace)}g(t,"create"),e.create=t,g(n,"is"),e.is=n}(Dr||(Dr={})),(bi=Lr||(Lr={})).asIs=1,bi.adjustIndentation=2,function(e){function t(e){var t=e;return t&&(Si.string(t.detail)||void 0===t.detail)&&(Si.string(t.description)||void 0===t.description)}g(t,"is"),e.is=t}(Ar||(Ar={})),function(e){function t(e){return{label:e}}g(t,"create"),e.create=t}(Mr||(Mr={})),function(e){function t(e,t){return{items:e||[],isIncomplete:!!t}}g(t,"create"),e.create=t}(Rr||(Rr={})),function(e){function t(e){return e.replace(/[\\`*_{}[\]()#+\-.!]/g,"\\$&")}function n(e){var t=e;return Si.string(t)||Si.objectLiteral(t)&&Si.string(t.language)&&Si.string(t.value)}g(t,"fromPlainText"),e.fromPlainText=t,g(n,"is"),e.is=n}(Fr||(Fr={})),function(e){function t(e){var t=e;return!!t&&Si.objectLiteral(t)&&(Nr.is(t.contents)||Fr.is(t.contents)||Si.typedArray(t.contents,Fr.is))&&(void 0===e.range||Xn.is(e.range))}g(t,"is"),e.is=t}(Pr||(Pr={})),function(e){function t(e,t){return t?{label:e,documentation:t}:{label:e}}g(t,"create"),e.create=t}(jr||(jr={})),function(e){function t(e,t){for(var n=[],r=2;r=0;a--){var s=r[a],l=e.offsetAt(s.range.start),u=e.offsetAt(s.range.end);if(!(u<=o))throw new Error("Overlapping edit");n=n.substring(0,l)+s.newText+n.substring(u,n.length),o=l}return n}function i(e,t){if(e.length<=1)return e;var n=e.length/2|0,r=e.slice(0,n),o=e.slice(n);i(r,t),i(o,t);for(var a=0,s=0,l=0;a0&&e.push(t.length),this._lineOffsets=e}return this._lineOffsets},e.prototype.positionAt=function(e){e=Math.max(Math.min(e,this._content.length),0);var t=this.getLineOffsets(),n=0,r=t.length;if(0===r)return Qn.create(0,e);for(;ne?r=i:n=i+1}var o=n-1;return Qn.create(o,e-t[o])},e.prototype.offsetAt=function(e){var t=this.getLineOffsets();if(e.line>=t.length)return this._content.length;if(e.line<0)return 0;var n=t[e.line],r=e.line+1this._start,this.getCurrentPosition=()=>this._pos,this.eol=()=>this._sourceText.length===this._pos,this.sol=()=>0===this._pos,this.peek=()=>this._sourceText.charAt(this._pos)||null,this.next=()=>{const e=this._sourceText.charAt(this._pos);return this._pos++,e},this.eat=e=>{if(this._testNextCharacter(e))return this._start=this._pos,this._pos++,this._sourceText.charAt(this._pos-1)},this.eatWhile=e=>{let t=this._testNextCharacter(e),n=!1;for(t&&(n=t,this._start=this._pos);t;)this._pos++,t=this._testNextCharacter(e),n=!0;return n},this.eatSpace=()=>this.eatWhile(/[\s\u00a0]/),this.skipToEnd=()=>{this._pos=this._sourceText.length},this.skipTo=e=>{this._pos=e},this.match=function(e){let n=!(arguments.length>1&&void 0!==arguments[1])||arguments[1],r=null,i=null;return"string"==typeof e?(i=new RegExp(e,arguments.length>2&&void 0!==arguments[2]&&arguments[2]?"i":"g").test(t._sourceText.slice(t._pos,t._pos+e.length)),r=e):e instanceof RegExp&&(i=t._sourceText.slice(t._pos).match(e),r=null==i?void 0:i[0]),!(null==i||!("string"==typeof e||i instanceof Array&&t._sourceText.startsWith(i[0],t._pos)))&&(n&&(t._start=t._pos,r&&r.length&&(t._pos+=r.length)),i)},this.backUp=e=>{this._pos-=e},this.column=()=>this._pos,this.indentation=()=>{const e=this._sourceText.match(/\s*/);let t=0;if(e&&0!==e.length){const n=e[0];let r=0;for(;n.length>r;)9===n.charCodeAt(r)?t+=2:t++,r++}return t},this.current=()=>this._sourceText.slice(this._start,this._pos),this._start=0,this._pos=0,this._sourceText=e}_testNextCharacter(e){const t=this._sourceText.charAt(this._pos);let n=!1;return n="string"==typeof e?t===e:e instanceof RegExp?e.test(t):e(t),n}}function _i(e){return{ofRule:e}}function Oi(e,t){return{ofRule:e,isList:!0,separator:t}}function Ii(e,t){const n=e.match;return e.match=e=>{let r=!1;return n&&(r=n(e)),r&&t.every((t=>t.match&&!t.match(e)))},e}function Di(e,t){return{style:t,match:t=>t.kind===e}}function Li(e,t){return{style:t||"punctuation",match:t=>"Punctuation"===t.kind&&t.value===e}}e.C=Ni,g(Ni,"CharacterStream"),g(_i,"opt"),g(Oi,"list$1"),g(Ii,"butNot"),g(Di,"t$2"),g(Li,"p$1");const Ai=g((e=>" "===e||"\t"===e||","===e||"\n"===e||"\r"===e||"\ufeff"===e||" "===e),"isIgnored");e.i=Ai;const Mi={Name:/^[_A-Za-z][_0-9A-Za-z]*/,Punctuation:/^(?:!|\$|\(|\)|\.\.\.|:|=|&|@|\[|]|\{|\||\})/,Number:/^-?(?:0|(?:[1-9][0-9]*))(?:\.[0-9]*)?(?:[eE][+-]?[0-9]+)?/,String:/^(?:"""(?:\\"""|[^"]|"[^"]|""[^"])*(?:""")?|"(?:[^"\\]|\\(?:"|\/|\\|b|f|n|r|t|u[0-9a-fA-F]{4}))*"?)/,Comment:/^#.*/};e.L=Mi;const Ri={Document:[Oi("Definition")],Definition(e){switch(e.value){case"{":return"ShortQuery";case"query":return"Query";case"mutation":return"Mutation";case"subscription":return"Subscription";case"fragment":return r.Kind.FRAGMENT_DEFINITION;case"schema":return"SchemaDef";case"scalar":return"ScalarDef";case"type":return"ObjectTypeDef";case"interface":return"InterfaceDef";case"union":return"UnionDef";case"enum":return"EnumDef";case"input":return"InputDef";case"extend":return"ExtendDef";case"directive":return"DirectiveDef"}},ShortQuery:["SelectionSet"],Query:[Fi("query"),_i(Pi("def")),_i("VariableDefinitions"),Oi("Directive"),"SelectionSet"],Mutation:[Fi("mutation"),_i(Pi("def")),_i("VariableDefinitions"),Oi("Directive"),"SelectionSet"],Subscription:[Fi("subscription"),_i(Pi("def")),_i("VariableDefinitions"),Oi("Directive"),"SelectionSet"],VariableDefinitions:[Li("("),Oi("VariableDefinition"),Li(")")],VariableDefinition:["Variable",Li(":"),"Type",_i("DefaultValue")],Variable:[Li("$","variable"),Pi("variable")],DefaultValue:[Li("="),"Value"],SelectionSet:[Li("{"),Oi("Selection"),Li("}")],Selection(e,t){return"..."===e.value?t.match(/[\s\u00a0,]*(on\b|@|{)/,!1)?"InlineFragment":"FragmentSpread":t.match(/[\s\u00a0,]*:/,!1)?"AliasedField":"Field"},AliasedField:[Pi("property"),Li(":"),Pi("qualifier"),_i("Arguments"),Oi("Directive"),_i("SelectionSet")],Field:[Pi("property"),_i("Arguments"),Oi("Directive"),_i("SelectionSet")],Arguments:[Li("("),Oi("Argument"),Li(")")],Argument:[Pi("attribute"),Li(":"),"Value"],FragmentSpread:[Li("..."),Pi("def"),Oi("Directive")],InlineFragment:[Li("..."),_i("TypeCondition"),Oi("Directive"),"SelectionSet"],FragmentDefinition:[Fi("fragment"),_i(Ii(Pi("def"),[Fi("on")])),"TypeCondition",Oi("Directive"),"SelectionSet"],TypeCondition:[Fi("on"),"NamedType"],Value(e){switch(e.kind){case"Number":return"NumberValue";case"String":return"StringValue";case"Punctuation":switch(e.value){case"[":return"ListValue";case"{":return"ObjectValue";case"$":return"Variable";case"&":return"NamedType"}return null;case"Name":switch(e.value){case"true":case"false":return"BooleanValue"}return"null"===e.value?"NullValue":"EnumValue"}},NumberValue:[Di("Number","number")],StringValue:[{style:"string",match:e=>"String"===e.kind,update(e,t){t.value.startsWith('"""')&&(e.inBlockstring=!t.value.slice(3).endsWith('"""'))}}],BooleanValue:[Di("Name","builtin")],NullValue:[Di("Name","keyword")],EnumValue:[Pi("string-2")],ListValue:[Li("["),Oi("Value"),Li("]")],ObjectValue:[Li("{"),Oi("ObjectField"),Li("}")],ObjectField:[Pi("attribute"),Li(":"),"Value"],Type(e){return"["===e.value?"ListType":"NonNullType"},ListType:[Li("["),"Type",Li("]"),_i(Li("!"))],NonNullType:["NamedType",_i(Li("!"))],NamedType:[ji("atom")],Directive:[Li("@","meta"),Pi("meta"),_i("Arguments")],DirectiveDef:[Fi("directive"),Li("@","meta"),Pi("meta"),_i("ArgumentsDef"),Fi("on"),Oi("DirectiveLocation",Li("|"))],InterfaceDef:[Fi("interface"),Pi("atom"),_i("Implements"),Oi("Directive"),Li("{"),Oi("FieldDef"),Li("}")],Implements:[Fi("implements"),Oi("NamedType",Li("&"))],DirectiveLocation:[Pi("string-2")],SchemaDef:[Fi("schema"),Oi("Directive"),Li("{"),Oi("OperationTypeDef"),Li("}")],OperationTypeDef:[Pi("keyword"),Li(":"),Pi("atom")],ScalarDef:[Fi("scalar"),Pi("atom"),Oi("Directive")],ObjectTypeDef:[Fi("type"),Pi("atom"),_i("Implements"),Oi("Directive"),Li("{"),Oi("FieldDef"),Li("}")],FieldDef:[Pi("property"),_i("ArgumentsDef"),Li(":"),"Type",Oi("Directive")],ArgumentsDef:[Li("("),Oi("InputValueDef"),Li(")")],InputValueDef:[Pi("attribute"),Li(":"),"Type",_i("DefaultValue"),Oi("Directive")],UnionDef:[Fi("union"),Pi("atom"),Oi("Directive"),Li("="),Oi("UnionMember",Li("|"))],UnionMember:["NamedType"],EnumDef:[Fi("enum"),Pi("atom"),Oi("Directive"),Li("{"),Oi("EnumValueDef"),Li("}")],EnumValueDef:[Pi("string-2"),Oi("Directive")],InputDef:[Fi("input"),Pi("atom"),Oi("Directive"),Li("{"),Oi("InputValueDef"),Li("}")],ExtendDef:[Fi("extend"),"ExtensionDefinition"],ExtensionDefinition(e){switch(e.value){case"schema":return r.Kind.SCHEMA_EXTENSION;case"scalar":return r.Kind.SCALAR_TYPE_EXTENSION;case"type":return r.Kind.OBJECT_TYPE_EXTENSION;case"interface":return r.Kind.INTERFACE_TYPE_EXTENSION;case"union":return r.Kind.UNION_TYPE_EXTENSION;case"enum":return r.Kind.ENUM_TYPE_EXTENSION;case"input":return r.Kind.INPUT_OBJECT_TYPE_EXTENSION}},[r.Kind.SCHEMA_EXTENSION]:["SchemaDef"],[r.Kind.SCALAR_TYPE_EXTENSION]:["ScalarDef"],[r.Kind.OBJECT_TYPE_EXTENSION]:["ObjectTypeDef"],[r.Kind.INTERFACE_TYPE_EXTENSION]:["InterfaceDef"],[r.Kind.UNION_TYPE_EXTENSION]:["UnionDef"],[r.Kind.ENUM_TYPE_EXTENSION]:["EnumDef"],[r.Kind.INPUT_OBJECT_TYPE_EXTENSION]:["InputDef"]};function Fi(e){return{style:"keyword",match:t=>"Name"===t.kind&&t.value===e}}function Pi(e){return{style:e,match:e=>"Name"===e.kind,update(e,t){e.name=t.value}}}function ji(e){return{style:e,match:e=>"Name"===e.kind,update(e,t){var n;(null===(n=e.prevState)||void 0===n?void 0:n.prevState)&&(e.name=t.value,e.prevState.prevState.type=t.value)}}}function Vi(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{eatWhitespace:e=>e.eatWhile(Ai),lexRules:Mi,parseRules:Ri,editorConfig:{}};return{startState(){const t={level:0,step:0,name:null,kind:null,type:null,rule:null,needsSeparator:!1,prevState:null};return qi(e.parseRules,t,r.Kind.DOCUMENT),t},token(t,n){return Ui(t,n,e)}}}function Ui(e,t,n){var r;if(t.inBlockstring)return e.match(/.*"""/)?(t.inBlockstring=!1,"string"):(e.skipToEnd(),"string");const{lexRules:i,parseRules:o,eatWhitespace:a,editorConfig:s}=n;if(t.rule&&0===t.rule.length?Hi(t):t.needsAdvance&&(t.needsAdvance=!1,Gi(t,!0)),e.sol()){const n=(null==s?void 0:s.tabSize)||2;t.indentLevel=Math.floor(e.indentation()/n)}if(a(e))return"ws";const l=Ki(i,e);if(!l)return e.match(/\S+/)||e.match(/\s/),qi($i,t,"Invalid"),"invalidchar";if("Comment"===l.kind)return qi($i,t,"Comment"),"comment";const u=Bi({},t);if("Punctuation"===l.kind)if(/^[{([]/.test(l.value))void 0!==t.indentLevel&&(t.levels=(t.levels||[]).concat(t.indentLevel+1));else if(/^[})\]]/.test(l.value)){const e=t.levels=(t.levels||[]).slice(0,-1);t.indentLevel&&e.length>0&&e.at(-1){const t=[];if(e)try{(0,r.visit)((0,r.parse)(e),{FragmentDefinition(e){t.push(e)}})}catch(e){return[]}return t}),"collectFragmentDefs"),Ji=[r.Kind.SCHEMA_DEFINITION,r.Kind.OPERATION_TYPE_DEFINITION,r.Kind.SCALAR_TYPE_DEFINITION,r.Kind.OBJECT_TYPE_DEFINITION,r.Kind.INTERFACE_TYPE_DEFINITION,r.Kind.UNION_TYPE_DEFINITION,r.Kind.ENUM_TYPE_DEFINITION,r.Kind.INPUT_OBJECT_TYPE_DEFINITION,r.Kind.DIRECTIVE_DEFINITION,r.Kind.SCHEMA_EXTENSION,r.Kind.SCALAR_TYPE_EXTENSION,r.Kind.OBJECT_TYPE_EXTENSION,r.Kind.INTERFACE_TYPE_EXTENSION,r.Kind.UNION_TYPE_EXTENSION,r.Kind.ENUM_TYPE_EXTENSION,r.Kind.INPUT_OBJECT_TYPE_EXTENSION],Zi=g((e=>{let t=!1;if(e)try{(0,r.visit)((0,r.parse)(e),{enter(e){if("Document"!==e.kind)return!!Ji.includes(e.kind)&&(t=!0,r.BREAK)}})}catch(e){return t}return t}),"hasTypeSystemDefinitions");function eo(e,t,n,i,o,a){var s;const l=Object.assign(Object.assign({},a),{schema:e}),u=i||vo(t,n),c="Invalid"===u.state.kind?u.state.prevState:u.state,d=(null==a?void 0:a.mode)||Co(t,null==a?void 0:a.uri);if(!c)return[];const{kind:f,step:p,prevState:h}=c,m=Eo(e,u.state);if(f===Qi.DOCUMENT)return d===To.TYPE_SYSTEM?ro(u):io(u);if(f===Qi.EXTEND_DEF)return oo(u);if((null===(s=null==h?void 0:h.prevState)||void 0===s?void 0:s.kind)===Qi.EXTENSION_DEFINITION&&c.name)return Vn(u,[]);if((null==h?void 0:h.kind)===r.Kind.SCALAR_TYPE_EXTENSION)return Vn(u,Object.values(e.getTypeMap()).filter(r.isScalarType).map((e=>({label:e.name,kind:xi.Function}))));if((null==h?void 0:h.kind)===r.Kind.OBJECT_TYPE_EXTENSION)return Vn(u,Object.values(e.getTypeMap()).filter((e=>(0,r.isObjectType)(e)&&!e.name.startsWith("__"))).map((e=>({label:e.name,kind:xi.Function}))));if((null==h?void 0:h.kind)===r.Kind.INTERFACE_TYPE_EXTENSION)return Vn(u,Object.values(e.getTypeMap()).filter(r.isInterfaceType).map((e=>({label:e.name,kind:xi.Function}))));if((null==h?void 0:h.kind)===r.Kind.UNION_TYPE_EXTENSION)return Vn(u,Object.values(e.getTypeMap()).filter(r.isUnionType).map((e=>({label:e.name,kind:xi.Function}))));if((null==h?void 0:h.kind)===r.Kind.ENUM_TYPE_EXTENSION)return Vn(u,Object.values(e.getTypeMap()).filter((e=>(0,r.isEnumType)(e)&&!e.name.startsWith("__"))).map((e=>({label:e.name,kind:xi.Function}))));if((null==h?void 0:h.kind)===r.Kind.INPUT_OBJECT_TYPE_EXTENSION)return Vn(u,Object.values(e.getTypeMap()).filter(r.isInputObjectType).map((e=>({label:e.name,kind:xi.Function}))));if(f===Qi.IMPLEMENTS||f===Qi.NAMED_TYPE&&(null==h?void 0:h.kind)===Qi.IMPLEMENTS)return lo(u,c,e,t,m);if(f===Qi.SELECTION_SET||f===Qi.FIELD||f===Qi.ALIASED_FIELD)return ao(u,m,l);if(f===Qi.ARGUMENTS||f===Qi.ARGUMENT&&0===p){const{argDefs:e}=m;if(e)return Vn(u,e.map((e=>{var t;return{label:e.name,insertText:e.name+": ",command:Xi,detail:String(e.type),documentation:null!==(t=e.description)&&void 0!==t?t:void 0,kind:xi.Variable,type:e.type}})))}if((f===Qi.OBJECT_VALUE||f===Qi.OBJECT_FIELD&&0===p)&&m.objectFieldDefs){const e=jn(m.objectFieldDefs),t=f===Qi.OBJECT_VALUE?xi.Value:xi.Field;return Vn(u,e.map((e=>{var n;return{label:e.name,detail:String(e.type),documentation:null!==(n=e.description)&&void 0!==n?n:void 0,kind:t,type:e.type}})))}if(f===Qi.ENUM_VALUE||f===Qi.LIST_VALUE&&1===p||f===Qi.OBJECT_FIELD&&2===p||f===Qi.ARGUMENT&&2===p)return so(u,m,t,e);if(f===Qi.VARIABLE&&1===p){const n=(0,r.getNamedType)(m.inputType);return Vn(u,po(t,e,u).filter((e=>e.detail===(null==n?void 0:n.name))))}if(f===Qi.TYPE_CONDITION&&1===p||f===Qi.NAMED_TYPE&&null!=h&&h.kind===Qi.TYPE_CONDITION)return uo(u,m,e);if(f===Qi.FRAGMENT_SPREAD&&1===p)return co(u,m,e,t,Array.isArray(o)?o:Yi(o));const g=So(c);if(d===To.TYPE_SYSTEM&&!g.needsAdvance&&f===Qi.NAMED_TYPE||f===Qi.LIST_TYPE){if(g.kind===Qi.FIELD_DEF)return Vn(u,Object.values(e.getTypeMap()).filter((e=>(0,r.isOutputType)(e)&&!e.name.startsWith("__"))).map((e=>({label:e.name,kind:xi.Function}))));if(g.kind===Qi.INPUT_VALUE_DEF)return Vn(u,Object.values(e.getTypeMap()).filter((e=>(0,r.isInputType)(e)&&!e.name.startsWith("__"))).map((e=>({label:e.name,kind:xi.Function}))))}return f===Qi.VARIABLE_DEFINITION&&2===p||f===Qi.LIST_TYPE&&1===p||f===Qi.NAMED_TYPE&&h&&(h.kind===Qi.VARIABLE_DEFINITION||h.kind===Qi.LIST_TYPE||h.kind===Qi.NON_NULL_TYPE)?mo(u,e):f===Qi.DIRECTIVE?go(u,c,e):[]}g(eo,"getAutocompleteSuggestions");const to=" {\n $1\n}",no=g((e=>{const{type:t}=e;if((0,r.isCompositeType)(t))return to;if((0,r.isListType)(t)&&(0,r.isCompositeType)(t.ofType))return to;if((0,r.isNonNullType)(t)){if((0,r.isCompositeType)(t.ofType))return to;if((0,r.isListType)(t.ofType)&&(0,r.isCompositeType)(t.ofType.ofType))return to}return null}),"getInsertText");function ro(e){return Vn(e,[{label:"extend",kind:xi.Function},{label:"type",kind:xi.Function},{label:"interface",kind:xi.Function},{label:"union",kind:xi.Function},{label:"input",kind:xi.Function},{label:"scalar",kind:xi.Function},{label:"schema",kind:xi.Function}])}function io(e){return Vn(e,[{label:"query",kind:xi.Function},{label:"mutation",kind:xi.Function},{label:"subscription",kind:xi.Function},{label:"fragment",kind:xi.Function},{label:"{",kind:xi.Constructor}])}function oo(e){return Vn(e,[{label:"type",kind:xi.Function},{label:"interface",kind:xi.Function},{label:"union",kind:xi.Function},{label:"input",kind:xi.Function},{label:"scalar",kind:xi.Function},{label:"schema",kind:xi.Function}])}function ao(e,t,n){var i;if(t.parentType){const{parentType:o}=t;let a=[];return"getFields"in o&&(a=jn(o.getFields())),(0,r.isCompositeType)(o)&&a.push(r.TypeNameMetaFieldDef),o===(null===(i=null==n?void 0:n.schema)||void 0===i?void 0:i.getQueryType())&&a.push(r.SchemaMetaFieldDef,r.TypeMetaFieldDef),Vn(e,a.map(((e,t)=>{var r;const i={sortText:String(t)+e.name,label:e.name,detail:String(e.type),documentation:null!==(r=e.description)&&void 0!==r?r:void 0,deprecated:Boolean(e.deprecationReason),isDeprecated:Boolean(e.deprecationReason),deprecationReason:e.deprecationReason,kind:xi.Field,type:e.type};if(null==n?void 0:n.fillLeafsOnComplete){const t=no(e);t&&(i.insertText=e.name+t,i.insertTextFormat=Or.Snippet,i.command=Xi)}return i})))}return[]}function so(e,t,n,i){const o=(0,r.getNamedType)(t.inputType),a=po(n,i,e).filter((e=>e.detail===o.name));return o instanceof r.GraphQLEnumType?Vn(e,o.getValues().map((e=>{var t;return{label:e.name,detail:String(o),documentation:null!==(t=e.description)&&void 0!==t?t:void 0,deprecated:Boolean(e.deprecationReason),isDeprecated:Boolean(e.deprecationReason),deprecationReason:e.deprecationReason,kind:xi.EnumMember,type:o}})).concat(a)):o===r.GraphQLBoolean?Vn(e,a.concat([{label:"true",detail:String(r.GraphQLBoolean),documentation:"Not false.",kind:xi.Variable,type:r.GraphQLBoolean},{label:"false",detail:String(r.GraphQLBoolean),documentation:"Not true.",kind:xi.Variable,type:r.GraphQLBoolean}])):a}function lo(e,t,n,i,o){if(t.needsSeparator)return[];const a=jn(n.getTypeMap()).filter(r.isInterfaceType),s=a.map((e=>{let{name:t}=e;return t})),l=new Set;yo(i,((e,t)=>{var i,a,u,c,d;if(t.name&&(t.kind!==Qi.INTERFACE_DEF||s.includes(t.name)||l.add(t.name),t.kind===Qi.NAMED_TYPE&&(null===(i=t.prevState)||void 0===i?void 0:i.kind)===Qi.IMPLEMENTS))if(o.interfaceDef){if(null===(a=o.interfaceDef)||void 0===a?void 0:a.getInterfaces().find((e=>{let{name:n}=e;return n===t.name})))return;const e=n.getType(t.name),i=null===(u=o.interfaceDef)||void 0===u?void 0:u.toConfig();o.interfaceDef=new r.GraphQLInterfaceType(Object.assign(Object.assign({},i),{interfaces:[...i.interfaces,e||new r.GraphQLInterfaceType({name:t.name,fields:{}})]}))}else if(o.objectTypeDef){if(null===(c=o.objectTypeDef)||void 0===c?void 0:c.getInterfaces().find((e=>{let{name:n}=e;return n===t.name})))return;const e=n.getType(t.name),i=null===(d=o.objectTypeDef)||void 0===d?void 0:d.toConfig();o.objectTypeDef=new r.GraphQLObjectType(Object.assign(Object.assign({},i),{interfaces:[...i.interfaces,e||new r.GraphQLInterfaceType({name:t.name,fields:{}})]}))}}));const u=o.interfaceDef||o.objectTypeDef,c=((null==u?void 0:u.getInterfaces())||[]).map((e=>{let{name:t}=e;return t}));return Vn(e,a.concat([...l].map((e=>({name:e})))).filter((e=>{let{name:t}=e;return t!==(null==u?void 0:u.name)&&!c.includes(t)})).map((e=>{const t={label:e.name,kind:xi.Interface,type:e};return(null==e?void 0:e.description)&&(t.documentation=e.description),t})))}function uo(e,t,n,i){let o;if(t.parentType)if((0,r.isAbstractType)(t.parentType)){const e=(0,r.assertAbstractType)(t.parentType),i=n.getPossibleTypes(e),a=Object.create(null);for(const e of i)for(const t of e.getInterfaces())a[t.name]=t;o=i.concat(jn(a))}else o=[t.parentType];else o=jn(n.getTypeMap()).filter((e=>(0,r.isCompositeType)(e)&&!e.name.startsWith("__")));return Vn(e,o.map((e=>{const t=(0,r.getNamedType)(e);return{label:String(e),documentation:(null==t?void 0:t.description)||"",kind:xi.Field}})))}function co(e,t,n,i,o){if(!i)return[];const a=n.getTypeMap(),s=Rn(e.state),l=ho(i);return o&&o.length>0&&l.push(...o),Vn(e,l.filter((e=>a[e.typeCondition.name.value]&&!(s&&s.kind===Qi.FRAGMENT_DEFINITION&&s.name===e.name.value)&&(0,r.isCompositeType)(t.parentType)&&(0,r.isCompositeType)(a[e.typeCondition.name.value])&&(0,r.doTypesOverlap)(n,t.parentType,a[e.typeCondition.name.value]))).map((e=>({label:e.name.value,detail:String(a[e.typeCondition.name.value]),documentation:`fragment ${e.name.value} on ${e.typeCondition.name.value}`,kind:xi.Field,type:a[e.typeCondition.name.value]}))))}g(ro,"getSuggestionsForTypeSystemDefinitions"),g(io,"getSuggestionsForExecutableDefinitions"),g(oo,"getSuggestionsForExtensionDefinitions"),g(ao,"getSuggestionsForFieldNames"),g(so,"getSuggestionsForInputValues"),g(lo,"getSuggestionsForImplements"),g(uo,"getSuggestionsForFragmentTypeConditions"),g(co,"getSuggestionsForFragmentSpread");const fo=g(((e,t)=>{var n,r,i,o,a,s,l,u,c,d;return(null===(n=e.prevState)||void 0===n?void 0:n.kind)===t?e.prevState:(null===(i=null===(r=e.prevState)||void 0===r?void 0:r.prevState)||void 0===i?void 0:i.kind)===t?e.prevState.prevState:(null===(s=null===(a=null===(o=e.prevState)||void 0===o?void 0:o.prevState)||void 0===a?void 0:a.prevState)||void 0===s?void 0:s.kind)===t?e.prevState.prevState.prevState:(null===(d=null===(c=null===(u=null===(l=e.prevState)||void 0===l?void 0:l.prevState)||void 0===u?void 0:u.prevState)||void 0===c?void 0:c.prevState)||void 0===d?void 0:d.kind)===t?e.prevState.prevState.prevState.prevState:void 0}),"getParentDefinition");function po(e,t,n){let r,i=null;const o=Object.create({});return yo(e,((e,a)=>{if((null==a?void 0:a.kind)===Qi.VARIABLE&&a.name&&(i=a.name),(null==a?void 0:a.kind)===Qi.NAMED_TYPE&&i){const e=fo(a,Qi.TYPE);(null==e?void 0:e.type)&&(r=t.getType(null==e?void 0:e.type))}i&&r&&!o[i]&&(o[i]={detail:r.toString(),insertText:"$"===n.string?i:"$"+i,label:i,type:r,kind:xi.Variable},i=null,r=null)})),jn(o)}function ho(e){const t=[];return yo(e,((e,n)=>{n.kind===Qi.FRAGMENT_DEFINITION&&n.name&&n.type&&t.push({kind:Qi.FRAGMENT_DEFINITION,name:{kind:r.Kind.NAME,value:n.name},selectionSet:{kind:Qi.SELECTION_SET,selections:[]},typeCondition:{kind:Qi.NAMED_TYPE,name:{kind:r.Kind.NAME,value:n.type}}})})),t}function mo(e,t,n){return Vn(e,jn(t.getTypeMap()).filter(r.isInputType).map((e=>({label:e.name,documentation:e.description,kind:xi.Variable}))))}function go(e,t,n,r){var i;return(null===(i=t.prevState)||void 0===i?void 0:i.kind)?Vn(e,n.getDirectives().filter((e=>bo(t.prevState,e))).map((e=>({label:e.name,documentation:e.description||"",kind:xi.Function})))):[]}function vo(e,t){let n=null,r=null,i=null;const o=yo(e,((e,o,a,s)=>{if(s===t.line&&e.getCurrentPosition()>=t.character)return n=a,r=Object.assign({},o),i=e.current(),"BREAK"}));return{start:o.start,end:o.end,string:i||o.string,state:r||o.state,style:n||o.style}}function yo(e,t){const n=e.split("\n"),r=Vi();let i=r.startState(),o="",a=new Ni("");for(let e=0;e{var h;switch(t.kind){case Qi.QUERY:case"ShortQuery":f=e.getQueryType();break;case Qi.MUTATION:f=e.getMutationType();break;case Qi.SUBSCRIPTION:f=e.getSubscriptionType();break;case Qi.INLINE_FRAGMENT:case Qi.FRAGMENT_DEFINITION:t.type&&(f=e.getType(t.type));break;case Qi.FIELD:case Qi.ALIASED_FIELD:f&&t.name?(s=d?Fn(e,d,t.name):null,f=s?s.type:null):s=null;break;case Qi.SELECTION_SET:d=(0,r.getNamedType)(f);break;case Qi.DIRECTIVE:o=t.name?e.getDirective(t.name):null;break;case Qi.INTERFACE_DEF:t.name&&(u=null,p=new r.GraphQLInterfaceType({name:t.name,interfaces:[],fields:{}}));break;case Qi.OBJECT_TYPE_DEF:t.name&&(p=null,u=new r.GraphQLObjectType({name:t.name,interfaces:[],fields:{}}));break;case Qi.ARGUMENTS:if(t.prevState)switch(t.prevState.kind){case Qi.FIELD:i=s&&s.args;break;case Qi.DIRECTIVE:i=o&&o.args;break;case Qi.ALIASED_FIELD:{const n=null===(h=t.prevState)||void 0===h?void 0:h.name;if(!n){i=null;break}const r=d?Fn(e,d,n):null;if(!r){i=null;break}i=r.args;break}default:i=null}else i=null;break;case Qi.ARGUMENT:if(i)for(let e=0;ee.value===t.name)):null;break;case Qi.LIST_VALUE:const g=(0,r.getNullableType)(l);l=g instanceof r.GraphQLList?g.ofType:null;break;case Qi.OBJECT_VALUE:const v=(0,r.getNamedType)(l);c=v instanceof r.GraphQLInputObjectType?v.getFields():null;break;case Qi.OBJECT_FIELD:const y=t.name&&c?c[t.name]:null;l=null==y?void 0:y.type;break;case Qi.NAMED_TYPE:t.name&&(f=e.getType(t.name))}})),{argDef:n,argDefs:i,directiveDef:o,enumValue:a,fieldDef:s,inputType:l,objectFieldDefs:c,parentType:d,type:f,interfaceDef:p,objectTypeDef:u}}var To,wo;function Co(e,t){return(null==t?void 0:t.endsWith(".graphqls"))||Zi(e)?To.TYPE_SYSTEM:To.EXECUTABLE}function So(e){return e.prevState&&e.kind&&[Qi.NAMED_TYPE,Qi.LIST_TYPE,Qi.TYPE,Qi.NON_NULL_TYPE].includes(e.kind)?So(e.prevState):e}g(po,"getVariableCompletions"),g(ho,"getFragmentDefinitions"),g(mo,"getSuggestionsForVariableDefinition"),g(go,"getSuggestionsForDirective"),g(vo,"getTokenAtPosition"),g(yo,"runOnlineParser"),g(bo,"canUseDirective"),g(Eo,"getTypeInfo"),(wo=To||(To={})).TYPE_SYSTEM="TYPE_SYSTEM",wo.EXECUTABLE="EXECUTABLE",g(Co,"getDocumentMode"),g(So,"unwrapType");var xo={exports:{}};function ko(e,t){if(null!=e)return e;var n=new Error(void 0!==t?t:"Got unexpected "+e);throw n.framesToPop=1,n}g(ko,"nullthrows"),xo.exports=ko,xo.exports.default=ko,Object.defineProperty(xo.exports,"__esModule",{value:!0});var No=Z(xo.exports);const _o=g(((e,t)=>{if(!t)return[];const n=new Map,i=new Set;(0,r.visit)(e,{FragmentDefinition(e){n.set(e.name.value,!0)},FragmentSpread(e){i.has(e.name.value)||i.add(e.name.value)}});const o=new Set;for(const e of i)!n.has(e)&&t.has(e)&&o.add(No(t.get(e)));const a=[];for(const e of o)(0,r.visit)(e,{FragmentSpread(e){!i.has(e.name.value)&&t.get(e.name.value)&&(o.add(No(t.get(e.name.value))),i.add(e.name.value))}}),n.has(e.name.value)||a.push(e);return a}),"getFragmentDependenciesForAST");function Oo(e,t){const n=Object.create(null);for(const i of t.definitions)if("OperationDefinition"===i.kind){const{variableDefinitions:t}=i;if(t)for(const{variable:i,type:o}of t){const t=(0,r.typeFromAST)(e,o);t?n[i.name.value]=t:o.kind===r.Kind.NAMED_TYPE&&"Float"===o.name.value&&(n[i.name.value]=r.GraphQLFloat)}}return n}function Io(e,t){const n=t?Oo(t,e):void 0,i=[];return(0,r.visit)(e,{OperationDefinition(e){i.push(e)}}),{variableToType:n,operations:i}}function Do(e,t){if(t)try{const n=(0,r.parse)(t);return Object.assign(Object.assign({},Io(n,e)),{documentAST:n})}catch(e){return}}g(Oo,"collectVariables"),g(Io,"getOperationASTFacts"),g(Do,"getOperationFacts"),globalThis&&globalThis.__awaiter;var Lo=g((function(e){return"object"==typeof e?null===e:"function"!=typeof e}),"isPrimitive"),Ao=g((function(e){return null!=e&&"object"==typeof e&&!1===Array.isArray(e)}),"isObject");function Mo(e){return!0===Ao(e)&&"[object Object]"===Object.prototype.toString.call(e)}g(Mo,"isObjectObject");var Ro=g((function(e){var t,n;return!1!==Mo(e)&&"function"==typeof(t=e.constructor)&&!1!==Mo(n=t.prototype)&&!1!==n.hasOwnProperty("isPrototypeOf")}),"isPlainObject");const{deleteProperty:Fo}=Reflect,Po=Lo,jo=Ro,Vo=g((e=>"object"==typeof e&&null!==e||"function"==typeof e),"isObject$1"),Uo=g((e=>"__proto__"===e||"constructor"===e||"prototype"===e),"isUnsafeKey"),Bo=g((e=>{if(!Po(e))throw new TypeError("Object keys must be strings or symbols");if(Uo(e))throw new Error(`Cannot set unsafe key: "${e}"`)}),"validateKey"),$o=g((e=>Array.isArray(e)?e.flat().map(String).join(","):e),"toStringKey"),qo=g(((e,t)=>{if("string"!=typeof e||!t)return e;let n=e+";";return void 0!==t.arrays&&(n+=`arrays=${t.arrays};`),void 0!==t.separator&&(n+=`separator=${t.separator};`),void 0!==t.split&&(n+=`split=${t.split};`),void 0!==t.merge&&(n+=`merge=${t.merge};`),void 0!==t.preservePaths&&(n+=`preservePaths=${t.preservePaths};`),n}),"createMemoKey"),Ho=g(((e,t,n)=>{const r=$o(t?qo(e,t):e);Bo(r);const i=Ko.cache.get(r)||n();return Ko.cache.set(r,i),i}),"memoize"),Go=g((function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const n=t.separator||".",r="/"!==n&&t.preservePaths;if("string"==typeof e&&!1!==r&&/\//.test(e))return[e];const i=[];let o="";const a=g((e=>{let t;""!==e.trim()&&Number.isInteger(t=Number(e))?i.push(t):i.push(e)}),"push");for(let t=0;tt&&"function"==typeof t.split?t.split(e):"symbol"==typeof e?[e]:Array.isArray(e)?e:Ho(e,t,(()=>Go(e,t)))),"split"),Wo=g(((e,t,n,r)=>{if(Bo(t),void 0===n)Fo(e,t);else if(r&&r.merge){const i="function"===r.merge?r.merge:Object.assign;i&&jo(e[t])&&jo(n)?e[t]=i(e[t],n):e[t]=n}else e[t]=n;return e}),"assignProp"),Ko=g(((e,t,n,r)=>{if(!t||!Vo(e))return e;const i=zo(t,r);let o=e;for(let e=0;e{Ko.cache=new Map};var Qo=Ko;function Xo(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 14 14",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("path",{d:"M5.0484 1.40838C6.12624 0.33054 7.87376 0.330541 8.9516 1.40838L12.5916 5.0484C13.6695 6.12624 13.6695 7.87376 12.5916 8.9516L8.9516 12.5916C7.87376 13.6695 6.12624 13.6695 5.0484 12.5916L1.40838 8.9516C0.33054 7.87376 0.330541 6.12624 1.40838 5.0484L5.0484 1.40838Z",stroke:"currentColor",strokeWidth:1.2}),t.createElement("rect",{x:6,y:6,width:2,height:2,rx:1,fill:"currentColor"}))}function Yo(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 14 9",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("path",{d:"M1 1L7 7L13 1",stroke:"currentColor",strokeWidth:1.5}))}function Jo(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 7 10",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("path",{d:"M6 1.04819L2 5.04819L6 9.04819",stroke:"currentColor",strokeWidth:1.75}))}function Zo(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 14 9",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("path",{d:"M13 8L7 2L1 8",stroke:"currentColor",strokeWidth:1.5}))}function ea(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 14 14",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("path",{d:"M1 1L12.9998 12.9997",stroke:"currentColor",strokeWidth:1.5}),t.createElement("path",{d:"M13 1L1.00079 13.0003",stroke:"currentColor",strokeWidth:1.5}))}function ta(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"-2 -2 22 22",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("path",{d:"M11.25 14.2105V15.235C11.25 16.3479 10.3479 17.25 9.23501 17.25H2.76499C1.65214 17.25 0.75 16.3479 0.75 15.235L0.75 8.76499C0.75 7.65214 1.65214 6.75 2.76499 6.75L3.78947 6.75",stroke:"currentColor",strokeWidth:1.5}),t.createElement("rect",{x:6.75,y:.75,width:10.5,height:10.5,rx:2.2069,stroke:"currentColor",strokeWidth:1.5}))}function na(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 14 14",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("path",{d:"M5.0484 1.40838C6.12624 0.33054 7.87376 0.330541 8.9516 1.40838L12.5916 5.0484C13.6695 6.12624 13.6695 7.87376 12.5916 8.9516L8.9516 12.5916C7.87376 13.6695 6.12624 13.6695 5.0484 12.5916L1.40838 8.9516C0.33054 7.87376 0.330541 6.12624 1.40838 5.0484L5.0484 1.40838Z",stroke:"currentColor",strokeWidth:1.2}),t.createElement("path",{d:"M5 9L9 5",stroke:"currentColor",strokeWidth:1.2}),t.createElement("path",{d:"M5 5L9 9",stroke:"currentColor",strokeWidth:1.2}))}function ra(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 12 12",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("path",{d:"M4 8L8 4",stroke:"currentColor",strokeWidth:1.2}),t.createElement("path",{d:"M4 4L8 8",stroke:"currentColor",strokeWidth:1.2}),t.createElement("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M8.5 1.2H9C9.99411 1.2 10.8 2.00589 10.8 3V9C10.8 9.99411 9.99411 10.8 9 10.8H8.5V12H9C10.6569 12 12 10.6569 12 9V3C12 1.34315 10.6569 0 9 0H8.5V1.2ZM3.5 1.2V0H3C1.34315 0 0 1.34315 0 3V9C0 10.6569 1.34315 12 3 12H3.5V10.8H3C2.00589 10.8 1.2 9.99411 1.2 9V3C1.2 2.00589 2.00589 1.2 3 1.2H3.5Z",fill:"currentColor"}))}function ia(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 12 12",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("rect",{x:.6,y:.6,width:10.8,height:10.8,rx:3.4,stroke:"currentColor",strokeWidth:1.2}),t.createElement("path",{d:"M4 8L8 4",stroke:"currentColor",strokeWidth:1.2}),t.createElement("path",{d:"M4 4L8 8",stroke:"currentColor",strokeWidth:1.2}))}function oa(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0.5 12 12",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("rect",{x:7,y:5.5,width:2,height:2,rx:1,transform:"rotate(90 7 5.5)",fill:"currentColor"}),t.createElement("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M10.8 9L10.8 9.5C10.8 10.4941 9.99411 11.3 9 11.3L3 11.3C2.00589 11.3 1.2 10.4941 1.2 9.5L1.2 9L-3.71547e-07 9L-3.93402e-07 9.5C-4.65826e-07 11.1569 1.34314 12.5 3 12.5L9 12.5C10.6569 12.5 12 11.1569 12 9.5L12 9L10.8 9ZM10.8 4L12 4L12 3.5C12 1.84315 10.6569 0.5 9 0.5L3 0.5C1.34315 0.5 -5.87117e-08 1.84315 -1.31135e-07 3.5L-1.5299e-07 4L1.2 4L1.2 3.5C1.2 2.50589 2.00589 1.7 3 1.7L9 1.7C9.99411 1.7 10.8 2.50589 10.8 3.5L10.8 4Z",fill:"currentColor"}))}function aa(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 20 24",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("path",{d:"M0.75 3C0.75 1.75736 1.75736 0.75 3 0.75H17.25C17.8023 0.75 18.25 1.19772 18.25 1.75V5.25",stroke:"currentColor",strokeWidth:1.5}),t.createElement("path",{d:"M0.75 3C0.75 4.24264 1.75736 5.25 3 5.25H18.25C18.8023 5.25 19.25 5.69771 19.25 6.25V22.25C19.25 22.8023 18.8023 23.25 18.25 23.25H3C1.75736 23.25 0.75 22.2426 0.75 21V3Z",stroke:"currentColor",strokeWidth:1.5}),t.createElement("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M3 5.25C1.75736 5.25 0.75 4.24264 0.75 3V21C0.75 22.2426 1.75736 23.25 3 23.25H18.25C18.8023 23.25 19.25 22.8023 19.25 22.25V6.25C19.25 5.69771 18.8023 5.25 18.25 5.25H3ZM13 11L6 11V12.5L13 12.5V11Z",fill:"currentColor"}))}function sa(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 20 24",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("path",{d:"M0.75 3C0.75 4.24264 1.75736 5.25 3 5.25H17.25M0.75 3C0.75 1.75736 1.75736 0.75 3 0.75H16.25C16.8023 0.75 17.25 1.19772 17.25 1.75V5.25M0.75 3V21C0.75 22.2426 1.75736 23.25 3 23.25H18.25C18.8023 23.25 19.25 22.8023 19.25 22.25V6.25C19.25 5.69771 18.8023 5.25 18.25 5.25H17.25",stroke:"currentColor",strokeWidth:1.5}),t.createElement("line",{x1:13,y1:11.75,x2:6,y2:11.75,stroke:"currentColor",strokeWidth:1.5}))}function la(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 12 12",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("rect",{x:5,y:5,width:2,height:2,rx:1,fill:"currentColor"}),t.createElement("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M8.5 1.2H9C9.99411 1.2 10.8 2.00589 10.8 3V9C10.8 9.99411 9.99411 10.8 9 10.8H8.5V12H9C10.6569 12 12 10.6569 12 9V3C12 1.34315 10.6569 0 9 0H8.5V1.2ZM3.5 1.2V0H3C1.34315 0 0 1.34315 0 3V9C0 10.6569 1.34315 12 3 12H3.5V10.8H3C2.00589 10.8 1.2 9.99411 1.2 9V3C1.2 2.00589 2.00589 1.2 3 1.2H3.5Z",fill:"currentColor"}))}function ua(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 12 13",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("rect",{x:.6,y:1.1,width:10.8,height:10.8,rx:2.4,stroke:"currentColor",strokeWidth:1.2}),t.createElement("rect",{x:5,y:5.5,width:2,height:2,rx:1,fill:"currentColor"}))}function ca(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 24 20",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("path",{d:"M1.59375 9.52344L4.87259 12.9944L8.07872 9.41249",stroke:"currentColor",strokeWidth:1.5,strokeLinecap:"square"}),t.createElement("path",{d:"M13.75 5.25V10.75H18.75",stroke:"currentColor",strokeWidth:1.5,strokeLinecap:"square"}),t.createElement("path",{d:"M4.95427 11.9332C4.55457 10.0629 4.74441 8.11477 5.49765 6.35686C6.25089 4.59894 7.5305 3.11772 9.16034 2.11709C10.7902 1.11647 12.6901 0.645626 14.5986 0.769388C16.5071 0.893151 18.3303 1.60543 19.8172 2.80818C21.3042 4.01093 22.3818 5.64501 22.9017 7.48548C23.4216 9.32595 23.3582 11.2823 22.7203 13.0853C22.0824 14.8883 20.9013 16.4492 19.3396 17.5532C17.778 18.6572 15.9125 19.25 14 19.25",stroke:"currentColor",strokeWidth:1.5}))}function da(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 12 12",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("circle",{cx:6,cy:6,r:5.4,stroke:"currentColor",strokeWidth:1.2,strokeDasharray:"4.241025 4.241025",transform:"rotate(22.5)","transform-origin":"center"}),t.createElement("circle",{cx:6,cy:6,r:1,fill:"currentColor"}))}function fa(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 19 18",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("path",{d:"M1.5 14.5653C1.5 15.211 1.75652 15.8303 2.21314 16.2869C2.66975 16.7435 3.28905 17 3.9348 17C4.58054 17 5.19984 16.7435 5.65646 16.2869C6.11307 15.8303 6.36959 15.211 6.36959 14.5653V12.1305H3.9348C3.28905 12.1305 2.66975 12.387 2.21314 12.8437C1.75652 13.3003 1.5 13.9195 1.5 14.5653Z",stroke:"currentColor",strokeWidth:1.125,strokeLinecap:"round",strokeLinejoin:"round"}),t.createElement("path",{d:"M3.9348 1.00063C3.28905 1.00063 2.66975 1.25715 2.21314 1.71375C1.75652 2.17035 1.5 2.78964 1.5 3.43537C1.5 4.0811 1.75652 4.70038 2.21314 5.15698C2.66975 5.61358 3.28905 5.8701 3.9348 5.8701H6.36959V3.43537C6.36959 2.78964 6.11307 2.17035 5.65646 1.71375C5.19984 1.25715 4.58054 1.00063 3.9348 1.00063Z",stroke:"currentColor",strokeWidth:1.125,strokeLinecap:"round",strokeLinejoin:"round"}),t.createElement("path",{d:"M15.0652 12.1305H12.6304V14.5653C12.6304 15.0468 12.7732 15.5175 13.0407 15.9179C13.3083 16.3183 13.6885 16.6304 14.1334 16.8147C14.5783 16.9989 15.0679 17.0472 15.5402 16.9532C16.0125 16.8593 16.4464 16.6274 16.7869 16.2869C17.1274 15.9464 17.3593 15.5126 17.4532 15.0403C17.5472 14.568 17.4989 14.0784 17.3147 13.6335C17.1304 13.1886 16.8183 12.8084 16.4179 12.5409C16.0175 12.2733 15.5468 12.1305 15.0652 12.1305Z",stroke:"currentColor",strokeWidth:1.125,strokeLinecap:"round",strokeLinejoin:"round"}),t.createElement("path",{d:"M12.6318 5.86775H6.36955V12.1285H12.6318V5.86775Z",stroke:"currentColor",strokeWidth:1.125,strokeLinecap:"round",strokeLinejoin:"round"}),t.createElement("path",{d:"M17.5 3.43473C17.5 2.789 17.2435 2.16972 16.7869 1.71312C16.3303 1.25652 15.711 1 15.0652 1C14.4195 1 13.8002 1.25652 13.3435 1.71312C12.8869 2.16972 12.6304 2.789 12.6304 3.43473V5.86946H15.0652C15.711 5.86946 16.3303 5.61295 16.7869 5.15635C17.2435 4.69975 17.5 4.08046 17.5 3.43473Z",stroke:"currentColor",strokeWidth:1.125,strokeLinecap:"round",strokeLinejoin:"round"}))}function pa(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 13 13",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("circle",{cx:5,cy:5,r:4.35,stroke:"currentColor",strokeWidth:1.3}),t.createElement("line",{x1:8.45962,y1:8.54038,x2:11.7525,y2:11.8333,stroke:"currentColor",strokeWidth:1.3}))}function ha(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"-2 -2 22 22",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("path",{d:"M17.2492 6V2.9569C17.2492 1.73806 16.2611 0.75 15.0423 0.75L2.9569 0.75C1.73806 0.75 0.75 1.73806 0.75 2.9569L0.75 6",stroke:"currentColor",strokeWidth:1.5}),t.createElement("path",{d:"M0.749873 12V15.0431C0.749873 16.2619 1.73794 17.25 2.95677 17.25H15.0421C16.261 17.25 17.249 16.2619 17.249 15.0431V12",stroke:"currentColor",strokeWidth:1.5}),t.createElement("path",{d:"M6 4.5L9 7.5L12 4.5",stroke:"currentColor",strokeWidth:1.5}),t.createElement("path",{d:"M12 13.5L9 10.5L6 13.5",stroke:"currentColor",strokeWidth:1.5}))}function ma(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 14 14",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("path",{d:"M0.75 13.25L0.0554307 12.967C-0.0593528 13.2488 0.00743073 13.5719 0.224488 13.7851C0.441545 13.9983 0.765869 14.0592 1.04549 13.9393L0.75 13.25ZM12.8214 1.83253L12.2911 2.36286L12.2911 2.36286L12.8214 1.83253ZM12.8214 3.90194L13.3517 4.43227L12.8214 3.90194ZM10.0981 1.17859L9.56773 0.648259L10.0981 1.17859ZM12.1675 1.17859L12.6978 0.648258L12.6978 0.648257L12.1675 1.17859ZM2.58049 8.75697L3.27506 9.03994L2.58049 8.75697ZM2.70066 8.57599L3.23099 9.10632L2.70066 8.57599ZM5.2479 11.4195L4.95355 10.7297L5.2479 11.4195ZM5.42036 11.303L4.89003 10.7727L5.42036 11.303ZM4.95355 10.7297C4.08882 11.0987 3.41842 11.362 2.73535 11.6308C2.05146 11.9 1.35588 12.1743 0.454511 12.5607L1.04549 13.9393C1.92476 13.5624 2.60256 13.2951 3.28469 13.0266C3.96762 12.7578 4.65585 12.4876 5.54225 12.1093L4.95355 10.7297ZM1.44457 13.533L3.27506 9.03994L1.88592 8.474L0.0554307 12.967L1.44457 13.533ZM3.23099 9.10632L10.6284 1.70892L9.56773 0.648259L2.17033 8.04566L3.23099 9.10632ZM11.6371 1.70892L12.2911 2.36286L13.3517 1.3022L12.6978 0.648258L11.6371 1.70892ZM12.2911 3.37161L4.89003 10.7727L5.95069 11.8333L13.3517 4.43227L12.2911 3.37161ZM12.2911 2.36286C12.5696 2.64142 12.5696 3.09305 12.2911 3.37161L13.3517 4.43227C14.2161 3.56792 14.2161 2.16654 13.3517 1.3022L12.2911 2.36286ZM10.6284 1.70892C10.9069 1.43036 11.3586 1.43036 11.6371 1.70892L12.6978 0.648257C11.8335 -0.216088 10.4321 -0.216084 9.56773 0.648259L10.6284 1.70892ZM3.27506 9.03994C3.26494 9.06479 3.24996 9.08735 3.23099 9.10632L2.17033 8.04566C2.04793 8.16806 1.95123 8.31369 1.88592 8.474L3.27506 9.03994ZM5.54225 12.1093C5.69431 12.0444 5.83339 11.9506 5.95069 11.8333L4.89003 10.7727C4.90863 10.7541 4.92988 10.7398 4.95355 10.7297L5.54225 12.1093Z",fill:"currentColor"}),t.createElement("path",{d:"M11.5 4.5L9.5 2.5",stroke:"currentColor",strokeWidth:1.4026,strokeLinecap:"round",strokeLinejoin:"round"}),t.createElement("path",{d:"M5.5 10.5L3.5 8.5",stroke:"currentColor",strokeWidth:1.4026,strokeLinecap:"round",strokeLinejoin:"round"}))}function ga(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 16 18",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("path",{d:"M1.32226e-07 1.6609C7.22332e-08 0.907329 0.801887 0.424528 1.46789 0.777117L15.3306 8.11621C16.0401 8.49182 16.0401 9.50818 15.3306 9.88379L1.46789 17.2229C0.801886 17.5755 1.36076e-06 17.0927 1.30077e-06 16.3391L1.32226e-07 1.6609Z",fill:"currentColor"}))}function va(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 10 16",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M4.25 9.25V13.5H5.75V9.25L10 9.25V7.75L5.75 7.75V3.5H4.25V7.75L0 7.75V9.25L4.25 9.25Z",fill:"currentColor"}))}function ya(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({width:25,height:25,viewBox:"0 0 25 25",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("path",{d:"M10.2852 24.0745L13.7139 18.0742",stroke:"currentColor",strokeWidth:1.5625}),t.createElement("path",{d:"M14.5742 24.0749L17.1457 19.7891",stroke:"currentColor",strokeWidth:1.5625}),t.createElement("path",{d:"M19.4868 24.0735L20.7229 21.7523C21.3259 20.6143 21.5457 19.3122 21.3496 18.0394C21.1535 16.7666 20.5519 15.591 19.6342 14.6874L23.7984 6.87853C24.0123 6.47728 24.0581 6.00748 23.9256 5.57249C23.7932 5.1375 23.4933 4.77294 23.0921 4.55901C22.6908 4.34509 22.221 4.29932 21.7861 4.43178C21.3511 4.56424 20.9865 4.86408 20.7726 5.26533L16.6084 13.0742C15.3474 12.8142 14.0362 12.9683 12.8699 13.5135C11.7035 14.0586 10.7443 14.9658 10.135 16.1L6 24.0735",stroke:"currentColor",strokeWidth:1.5625}),t.createElement("path",{d:"M4 15L5 13L7 12L5 11L4 9L3 11L1 12L3 13L4 15Z",stroke:"currentColor",strokeWidth:1.5625,strokeLinejoin:"round"}),t.createElement("path",{d:"M11.5 8L12.6662 5.6662L15 4.5L12.6662 3.3338L11.5 1L10.3338 3.3338L8 4.5L10.3338 5.6662L11.5 8Z",stroke:"currentColor",strokeWidth:1.5625,strokeLinejoin:"round"}))}function ba(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 16 16",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("path",{d:"M4.75 9.25H1.25V12.75",stroke:"currentColor",strokeWidth:1,strokeLinecap:"square"}),t.createElement("path",{d:"M11.25 6.75H14.75V3.25",stroke:"currentColor",strokeWidth:1,strokeLinecap:"square"}),t.createElement("path",{d:"M14.1036 6.65539C13.8 5.27698 13.0387 4.04193 11.9437 3.15131C10.8487 2.26069 9.48447 1.76694 8.0731 1.75043C6.66173 1.73392 5.28633 2.19563 4.17079 3.0604C3.05526 3.92516 2.26529 5.14206 1.92947 6.513",stroke:"currentColor",strokeWidth:1}),t.createElement("path",{d:"M1.89635 9.34461C2.20001 10.723 2.96131 11.9581 4.05631 12.8487C5.15131 13.7393 6.51553 14.2331 7.9269 14.2496C9.33827 14.2661 10.7137 13.8044 11.8292 12.9396C12.9447 12.0748 13.7347 10.8579 14.0705 9.487",stroke:"currentColor",strokeWidth:1}))}function Ea(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 13 13",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("rect",{x:.6,y:.6,width:11.8,height:11.8,rx:5.9,stroke:"currentColor",strokeWidth:1.2}),t.createElement("path",{d:"M4.25 7.5C4.25 6 5.75 5 6.5 6.5C7.25 8 8.75 7 8.75 5.5",stroke:"currentColor",strokeWidth:1.2}))}function Ta(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 21 20",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M9.29186 1.92702C9.06924 1.82745 8.87014 1.68202 8.70757 1.50024L7.86631 0.574931C7.62496 0.309957 7.30773 0.12592 6.95791 0.0479385C6.60809 -0.0300431 6.24274 0.00182978 5.91171 0.139208C5.58068 0.276585 5.3001 0.512774 5.10828 0.815537C4.91645 1.1183 4.82272 1.47288 4.83989 1.83089L4.90388 3.08019C4.91612 3.32348 4.87721 3.56662 4.78968 3.79394C4.70215 4.02126 4.56794 4.2277 4.39571 4.39994C4.22347 4.57219 4.01704 4.7064 3.78974 4.79394C3.56243 4.88147 3.3193 4.92038 3.07603 4.90814L1.8308 4.84414C1.47162 4.82563 1.11553 4.91881 0.811445 5.11086C0.507359 5.30292 0.270203 5.58443 0.132561 5.91671C-0.00508149 6.249 -0.0364554 6.61576 0.0427496 6.9666C0.121955 7.31744 0.307852 7.63514 0.5749 7.87606L1.50016 8.71204C1.68193 8.87461 1.82735 9.07373 1.92692 9.29636C2.02648 9.51898 2.07794 9.76012 2.07794 10.004C2.07794 10.2479 2.02648 10.489 1.92692 10.7116C1.82735 10.9343 1.68193 11.1334 1.50016 11.296L0.5749 12.1319C0.309856 12.3729 0.125575 12.6898 0.0471809 13.0393C-0.0312128 13.3888 9.64098e-05 13.754 0.13684 14.0851C0.273583 14.4162 0.509106 14.6971 0.811296 14.8894C1.11349 15.0817 1.46764 15.1762 1.82546 15.1599L3.0707 15.0959C3.31397 15.0836 3.5571 15.1225 3.7844 15.2101C4.01171 15.2976 4.21814 15.4318 4.39037 15.6041C4.56261 15.7763 4.69682 15.9827 4.78435 16.2101C4.87188 16.4374 4.91078 16.6805 4.89855 16.9238L4.83455 18.1691C4.81605 18.5283 4.90921 18.8844 5.10126 19.1885C5.2933 19.4926 5.5748 19.7298 5.90707 19.8674C6.23934 20.0051 6.60608 20.0365 6.9569 19.9572C7.30772 19.878 7.6254 19.6921 7.86631 19.4251L8.7129 18.4998C8.87547 18.318 9.07458 18.1725 9.29719 18.073C9.51981 17.9734 9.76093 17.9219 10.0048 17.9219C10.2487 17.9219 10.4898 17.9734 10.7124 18.073C10.935 18.1725 11.1341 18.318 11.2967 18.4998L12.1326 19.4251C12.3735 19.6921 12.6912 19.878 13.042 19.9572C13.3929 20.0365 13.7596 20.0051 14.0919 19.8674C14.4241 19.7298 14.7056 19.4926 14.8977 19.1885C15.0897 18.8844 15.1829 18.5283 15.1644 18.1691L15.1004 16.9238C15.0882 16.6805 15.1271 16.4374 15.2146 16.2101C15.3021 15.9827 15.4363 15.7763 15.6086 15.6041C15.7808 15.4318 15.9872 15.2976 16.2145 15.2101C16.4418 15.1225 16.685 15.0836 16.9282 15.0959L18.1735 15.1599C18.5326 15.1784 18.8887 15.0852 19.1928 14.8931C19.4969 14.7011 19.7341 14.4196 19.8717 14.0873C20.0093 13.755 20.0407 13.3882 19.9615 13.0374C19.8823 12.6866 19.6964 12.3689 19.4294 12.1279L18.5041 11.292C18.3223 11.1294 18.1769 10.9303 18.0774 10.7076C17.9778 10.485 17.9263 10.2439 17.9263 10C17.9263 9.75612 17.9778 9.51499 18.0774 9.29236C18.1769 9.06973 18.3223 8.87062 18.5041 8.70804L19.4294 7.87206C19.6964 7.63114 19.8823 7.31344 19.9615 6.9626C20.0407 6.61176 20.0093 6.245 19.8717 5.91271C19.7341 5.58043 19.4969 5.29892 19.1928 5.10686C18.8887 4.91481 18.5326 4.82163 18.1735 4.84014L16.9282 4.90414C16.685 4.91638 16.4418 4.87747 16.2145 4.78994C15.9872 4.7024 15.7808 4.56818 15.6086 4.39594C15.4363 4.2237 15.3021 4.01726 15.2146 3.78994C15.1271 3.56262 15.0882 3.31948 15.1004 3.07619L15.1644 1.83089C15.1829 1.4717 15.0897 1.11559 14.8977 0.811487C14.7056 0.507385 14.4241 0.270217 14.0919 0.132568C13.7596 -0.00508182 13.3929 -0.0364573 13.042 0.0427519C12.6912 0.121961 12.3735 0.307869 12.1326 0.574931L11.2914 1.50024C11.1288 1.68202 10.9297 1.82745 10.7071 1.92702C10.4845 2.02659 10.2433 2.07805 9.99947 2.07805C9.7556 2.07805 9.51448 2.02659 9.29186 1.92702ZM14.3745 10C14.3745 12.4162 12.4159 14.375 9.99977 14.375C7.58365 14.375 5.625 12.4162 5.625 10C5.625 7.58375 7.58365 5.625 9.99977 5.625C12.4159 5.625 14.3745 7.58375 14.3745 10Z",fill:"currentColor"}))}function wa(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 14 14",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("path",{d:"M6.5782 1.07092C6.71096 0.643026 7.28904 0.643027 7.4218 1.07092L8.59318 4.84622C8.65255 5.03758 8.82284 5.16714 9.01498 5.16714L12.8056 5.16714C13.2353 5.16714 13.4139 5.74287 13.0663 6.00732L9.99962 8.34058C9.84418 8.45885 9.77913 8.66848 9.83851 8.85984L11.0099 12.6351C11.1426 13.063 10.675 13.4189 10.3274 13.1544L7.26069 10.8211C7.10524 10.7029 6.89476 10.7029 6.73931 10.8211L3.6726 13.1544C3.32502 13.4189 2.85735 13.063 2.99012 12.6351L4.16149 8.85984C4.22087 8.66848 4.15582 8.45885 4.00038 8.34058L0.933671 6.00732C0.586087 5.74287 0.764722 5.16714 1.19436 5.16714L4.98502 5.16714C5.17716 5.16714 5.34745 5.03758 5.40682 4.84622L6.5782 1.07092Z",fill:"currentColor",stroke:"currentColor"}))}function Ca(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 14 14",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("path",{d:"M6.5782 1.07092C6.71096 0.643026 7.28904 0.643027 7.4218 1.07092L8.59318 4.84622C8.65255 5.03758 8.82284 5.16714 9.01498 5.16714L12.8056 5.16714C13.2353 5.16714 13.4139 5.74287 13.0663 6.00732L9.99962 8.34058C9.84418 8.45885 9.77913 8.66848 9.83851 8.85984L11.0099 12.6351C11.1426 13.063 10.675 13.4189 10.3274 13.1544L7.26069 10.8211C7.10524 10.7029 6.89476 10.7029 6.73931 10.8211L3.6726 13.1544C3.32502 13.4189 2.85735 13.063 2.99012 12.6351L4.16149 8.85984C4.22087 8.66848 4.15582 8.45885 4.00038 8.34058L0.933671 6.00732C0.586087 5.74287 0.764722 5.16714 1.19436 5.16714L4.98502 5.16714C5.17716 5.16714 5.34745 5.03758 5.40682 4.84622L6.5782 1.07092Z",stroke:"currentColor",strokeWidth:1.5}))}function Sa(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 16 16",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("rect",{width:16,height:16,rx:2,fill:"currentColor"}))}function xa(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 13 13",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("rect",{x:.6,y:.6,width:11.8,height:11.8,rx:5.9,stroke:"currentColor",strokeWidth:1.2}),t.createElement("rect",{x:5.5,y:5.5,width:2,height:2,rx:1,fill:"currentColor"}))}g(Xo,"SvgArgument"),g(Yo,"SvgChevronDown"),g(Jo,"SvgChevronLeft"),g(Zo,"SvgChevronUp"),g(ea,"SvgClose"),g(ta,"SvgCopy"),g(na,"SvgDeprecatedArgument"),g(ra,"SvgDeprecatedEnumValue"),g(ia,"SvgDeprecatedField"),g(oa,"SvgDirective"),g(aa,"SvgDocsFilled"),g(sa,"SvgDocs"),g(la,"SvgEnumValue"),g(ua,"SvgField"),g(ca,"SvgHistory"),g(da,"SvgImplements"),g(fa,"SvgKeyboardShortcut"),g(pa,"SvgMagnifyingGlass"),g(ha,"SvgMerge"),g(ma,"SvgPen"),g(ga,"SvgPlay"),g(va,"SvgPlus"),g(ya,"SvgPrettify"),g(ba,"SvgReload"),g(Ea,"SvgRootType"),g(Ta,"SvgSettings"),g(wa,"SvgStarFilled"),g(Ca,"SvgStar"),g(Sa,"SvgStop"),g(xa,"SvgType");var ka=Object.defineProperty,Na=g(((e,t)=>ka(e,"name",{value:t,configurable:!0})),"__name$E");const _a=is(Xo,"argument icon");e.ac=_a;const Oa=is(Yo,"chevron down icon");e.ad=Oa;const Ia=is(Jo,"chevron left icon");e.ae=Ia;const Da=is(Zo,"chevron up icon");e.af=Da;const La=is(ea,"close icon");e.ag=La;const Aa=is(ta,"copy icon");e.ah=Aa;const Ma=is(na,"deprecated argument icon");e.ai=Ma;const Ra=is(ra,"deprecated enum value icon");e.aj=Ra;const Fa=is(ia,"deprecated field icon");e.ak=Fa;const Pa=is(oa,"directive icon");e.al=Pa;const ja=is(aa,"filled docs icon");e.am=ja;const Va=is(sa,"docs icon");e.an=Va;const Ua=is(la,"enum value icon");e.ao=Ua;const Ba=is(ua,"field icon");e.ap=Ba;const $a=is(ca,"history icon");e.aq=$a;const qa=is(da,"implements icon");e.ar=qa;const Ha=is(fa,"keyboard shortcut icon");e.as=Ha;const Ga=is(pa,"magnifying glass icon");e.at=Ga;const za=is(ha,"merge icon");e.au=za;const Wa=is(ma,"pen icon");e.av=Wa;const Ka=is(ga,"play icon");e.aw=Ka;const Qa=is(va,"plus icon");e.ax=Qa;const Xa=is(ya,"prettify icon");e.ay=Xa;const Ya=is(ba,"reload icon");e.az=Ya;const Ja=is(Ea,"root type icon");e.aA=Ja;const Za=is(Ta,"settings icon");e.aB=Za;const es=is(wa,"filled star icon");e.aC=es;const ts=is(Ca,"star icon");e.aD=ts;const ns=is(Sa,"stop icon");e.aE=ns;const rs=is(xa,"type icon");function is(e,t){const n=Na(g((function(n){return de(e,m(h({},n),{title:t}))}),"IconComponent"),"IconComponent");return Object.defineProperty(n,"name",{value:e.name}),n}e.aF=rs,g(is,"generateIcon"),Na(is,"generateIcon");const os=(0,t.forwardRef)(((e,t)=>de("button",m(h({},e),{ref:t,className:b("graphiql-un-styled",e.className)}))));e.aG=os,os.displayName="UnStyledButton";const as=(0,t.forwardRef)(((e,t)=>de("button",m(h({},e),{ref:t,className:b("graphiql-button",{success:"graphiql-button-success",error:"graphiql-button-error"}[e.state],e.className)}))));e.aH=as,as.displayName="Button";const ss=(0,t.forwardRef)(((e,t)=>de("div",m(h({},e),{ref:t,className:b("graphiql-button-group",e.className)}))));function ls(){return!("undefined"==typeof window||!window.document||!window.document.createElement)}e.aI=ss,ss.displayName="ButtonGroup",g(ls,"canUseDOM");var us=ls()?t.useLayoutEffect:t.useEffect;function cs(){var e=(0,t.useState)(Object.create(null))[1];return(0,t.useCallback)((function(){e(Object.create(null))}),[])}function ds(e,t){if(null==e)return{};var n,r,i={},o=Object.keys(e);for(r=0;r=0||(i[n]=e[n]);return i}g(cs,"useForceUpdate"),g(ds,"_objectWithoutPropertiesLoose$b");var fs=["unstable_skipInitialRender"],ps=g((function(e){var n=e.children,r=e.type,o=void 0===r?"reach-portal":r,a=e.containerRef,s=(0,t.useRef)(null),l=(0,t.useRef)(null),u=cs();return us((function(){if(s.current){var e=s.current.ownerDocument,t=(null==a?void 0:a.current)||e.body;return l.current=null==e?void 0:e.createElement(o),t.appendChild(l.current),u(),function(){l.current&&t&&t.removeChild(l.current)}}}),[o,u,a]),l.current?(0,i.createPortal)(n,l.current):(0,t.createElement)("span",{ref:s})}),"PortalImpl"),hs=g((function(e){var n=e.unstable_skipInitialRender,r=ds(e,fs),i=(0,t.useState)(!1),o=i[0],a=i[1];return(0,t.useEffect)((function(){n&&a(!0)}),[n]),n&&!o?null:(0,t.createElement)(ps,r)}),"Portal");function ms(e){return ls()?e?e.ownerDocument:document:null}function gs(e){return"boolean"==typeof e}function vs(e){return!(!e||"[object Function]"!={}.toString.call(e))}function ys(e){return"string"==typeof e}function bs(){}function Es(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n=e.length?{done:!0}:{done:!1,value:e[r++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}return(n=e[Symbol.iterator]()).next.bind(n)}function Cs(e,t){if(null!=e)if(vs(e))e(t);else try{e.current=t}catch(n){throw new Error('Cannot assign value "'+t+'" to ref "'+e+'"')}}function Ss(){for(var e=arguments.length,n=new Array(e),r=0;r=0||(i[n]=e[n]);return i}function Ns(){return Ns=Object.assign?Object.assign.bind():function(e){for(var t=1;t=0})).sort(Tl)}),"orderByTabIndex"),Cl=["button:enabled","select:enabled","textarea:enabled","input:enabled","a[href]","area[href]","summary","iframe","object","embed","audio[controls]","video[controls]","[tabindex]","[contenteditable]","[autofocus]"].join(","),Sl="".concat(Cl,", [data-focus-guard]"),xl=g((function(e,t){var n;return rl((null===(n=e.shadowRoot)||void 0===n?void 0:n.children)||e.children).reduce((function(e,n){return e.concat(n.matches(t?Sl:Cl)?[n]:[],xl(n))}),[])}),"getFocusablesWithShadowDom"),kl=g((function(e,t){return e.reduce((function(e,n){return e.concat(xl(n,t),n.parentNode?rl(n.parentNode.querySelectorAll(Cl)).filter((function(e){return e===n})):[])}),[])}),"getFocusables"),Nl=g((function(e){var t=e.querySelectorAll("[".concat("data-autofocus-inside","]"));return rl(t).map((function(e){return kl([e])})).reduce((function(e,t){return e.concat(t)}),[])}),"getParentAutofocusables"),_l=g((function(e,t){return rl(e).filter((function(e){return ul(t,e)})).filter((function(e){return gl(e)}))}),"filterFocusable"),Ol=g((function(e,t){return void 0===t&&(t=new Map),rl(e).filter((function(e){return dl(t,e)}))}),"filterAutoFocusable"),Il=g((function(e,t,n){return wl(_l(kl(e,n),t),!0,n)}),"getTabbableNodes"),Dl=g((function(e,t){return wl(_l(kl(e),t),!1)}),"getAllTabbableNodes"),Ll=g((function(e,t){return _l(Nl(e),t)}),"parentAutofocusables"),Al=g((function(e,t){return(e.shadowRoot?Al(e.shadowRoot,t):Object.getPrototypeOf(e).contains.call(e,t))||rl(e.children).some((function(e){return Al(e,t)}))}),"contains"),Ml=g((function(e){for(var t=new Set,n=e.length,r=0;r0&&t.add(i),(o&Node.DOCUMENT_POSITION_CONTAINS)>0&&t.add(r)}return e.filter((function(e,n){return!t.has(n)}))}),"filterNested"),Rl=g((function(e){return e.parentNode?Rl(e.parentNode):e}),"getTopParent"),Fl=g((function(e){return il(e).filter(Boolean).reduce((function(e,t){var n=t.getAttribute(Ds);return e.push.apply(e,n?Ml(rl(Rl(t).querySelectorAll("[".concat(Ds,'="').concat(n,'"]:not([').concat(Ls,'="disabled"])')))):[t]),e}),[])}),"getAllAffectedNodes"),Pl=g((function(e){return e.activeElement?e.activeElement.shadowRoot?Pl(e.activeElement.shadowRoot):e.activeElement:void 0}),"getNestedShadowActiveElement"),jl=g((function(){return document.activeElement?document.activeElement.shadowRoot?Pl(document.activeElement.shadowRoot):document.activeElement:void 0}),"getActiveElement"),Vl=g((function(e){return e===document.activeElement}),"focusInFrame"),Ul=g((function(e){return Boolean(rl(e.querySelectorAll("iframe")).some((function(e){return Vl(e)})))}),"focusInsideIframe"),Bl=g((function(e){var t=document&&jl();return!(!t||t.dataset&&t.dataset.focusGuard)&&Fl(e).some((function(e){return Al(e,t)||Ul(e)}))}),"focusInside"),$l=g((function(){var e=document&&jl();return!!e&&rl(document.querySelectorAll("[".concat("data-no-focus-lock","]"))).some((function(t){return Al(t,e)}))}),"focusIsHidden"),ql=g((function(e,t){return t.filter(ml).filter((function(t){return t.name===e.name})).filter((function(e){return e.checked}))[0]||e}),"findSelectedRadio"),Hl=g((function(e,t){return ml(e)&&e.name?ql(e,t):e}),"correctNode"),Gl=g((function(e){var t=new Set;return e.forEach((function(n){return t.add(Hl(n,e))})),e.filter((function(e){return t.has(e)}))}),"correctNodes"),zl=g((function(e){return e[0]&&e.length>1?Hl(e[0],e):e[0]}),"pickFirstFocus"),Wl=g((function(e,t){return e.length>1?e.indexOf(Hl(e[t],e)):t}),"pickFocusable"),Kl="NEW_FOCUS",Ql=g((function(e,t,n,r){var i=e.length,o=e[0],a=e[i-1],s=yl(n);if(!(n&&e.indexOf(n)>=0)){var l=void 0!==n?t.indexOf(n):-1,u=r?t.indexOf(r):l,c=r?e.indexOf(r):-1,d=l-u,f=t.indexOf(o),p=t.indexOf(a),h=Gl(t),m=(void 0!==n?h.indexOf(n):-1)-(r?h.indexOf(r):l),g=Wl(e,0),v=Wl(e,i-1);return-1===l||-1===c?Kl:!d&&c>=0?c:l<=f&&s&&Math.abs(d)>1?v:l>=p&&s&&Math.abs(d)>1?g:d&&Math.abs(m)>1?c:l<=f?v:l>p?g:d?Math.abs(d)>1?c:(i+c+d)%i:void 0}}),"newFocus"),Xl=g((function(e,t){return void 0===t&&(t=[]),t.push(e),e.parentNode&&Xl(e.parentNode.host||e.parentNode,t),t}),"getParents"),Yl=g((function(e,t){for(var n=Xl(e),r=Xl(t),i=0;i=0)return o}return!1}),"getCommonParent"),Jl=g((function(e,t,n){var r=il(e),i=il(t),o=r[0],a=!1;return i.filter(Boolean).forEach((function(e){a=Yl(a||e,e)||a,n.filter(Boolean).forEach((function(e){var t=Yl(o,e);t&&(a=!a||Al(t,a)?t:Yl(t,a))}))})),a}),"getTopCommonParent"),Zl=g((function(e,t){return e.reduce((function(e,n){return e.concat(Ll(n,t))}),[])}),"allParentAutofocusables"),eu=g((function(e){return function(t){var n;return t.autofocus||!!(null===(n=fl(t))||void 0===n?void 0:n.autofocus)||e.indexOf(t)>=0}}),"findAutoFocused"),tu=g((function(e,t){var n=new Map;return t.forEach((function(e){return n.set(e.node,e)})),e.map((function(e){return n.get(e)})).filter(El)}),"reorderNodes"),nu=g((function(e,t){var n=document&&jl(),r=Fl(e).filter(bl),i=Jl(n||e,e,r),o=new Map,a=Dl(r,o),s=Il(r,o).filter((function(e){var t=e.node;return bl(t)}));if(s[0]||(s=a)[0]){var l=Dl([i],o).map((function(e){return e.node})),u=tu(l,s),c=u.map((function(e){return e.node})),d=Ql(c,l,n,t);if(d===Kl){var f=Ol(a.map((function(e){return e.node}))).filter(eu(Zl(r,o)));return{node:f&&f.length?zl(f):zl(Ol(c))}}return void 0===d?d:u[d]}}),"getFocusMerge"),ru=g((function(e){var t=Fl(e).filter(bl),n=Jl(e,e,t),r=new Map,i=Il([n],r,!0),o=Il(t,r).filter((function(e){var t=e.node;return bl(t)})).map((function(e){return e.node}));return i.map((function(e){var t=e.node;return{node:t,index:e.index,lockItem:o.indexOf(t)>=0,guard:yl(t)}}))}),"getFocusabledIn"),iu=g((function(e,t){"focus"in e&&e.focus(t),"contentWindow"in e&&e.contentWindow&&e.contentWindow.focus()}),"focusOn"),ou=0,au=!1,su=g((function(e,t,n){void 0===n&&(n={});var r=nu(e,t);if(!au&&r){if(ou>2)return console.error("FocusLock: focus-fighting detected. Only one focus management system could be active. See https://github.com/theKashey/focus-lock/#focus-fighting"),au=!0,void setTimeout((function(){au=!1}),1);ou++,iu(r.node,n.focusOptions),ou--}}),"setFocus");function lu(e){var t=window.setImmediate;void 0!==t?t(e):setTimeout(e,1)}g(lu,"deferAction");var uu=g((function(){return document&&document.activeElement===document.body}),"focusOnBody"),cu=g((function(){return uu()||$l()}),"isFreeFocus"),du=null,fu=null,pu=null,hu=!1,mu=g((function(){return!0}),"defaultWhitelist"),gu=g((function(e){return(du.whiteList||mu)(e)}),"focusWhitelisted"),vu=g((function(e,t){pu={observerNode:e,portaledElement:t}}),"recordPortal"),yu=g((function(e){return pu&&pu.portaledElement===e}),"focusIsPortaledPair");function bu(e,t,n,r){var i=null,o=e;do{var a=r[o];if(a.guard)a.node.dataset.focusAutoGuard&&(i=a);else{if(!a.lockItem)break;if(o!==e)return;i=null}}while((o+=n)!==t);i&&(i.node.tabIndex=0)}g(bu,"autoGuard");var Eu=g((function(e){return e&&"current"in e?e.current:e}),"extractRef"),Tu=g((function(e){return e?Boolean(hu):"meanwhile"===hu}),"focusWasOutside"),wu=g((function e(t,n,r){return n&&(n.host===t&&(!n.activeElement||r.contains(n.activeElement))||n.parentNode&&e(t,n.parentNode,r))}),"checkInHost"),Cu=g((function(e,t){return t.some((function(t){return wu(e,t,t)}))}),"withinHost"),Su=g((function(){var e=!1;if(du){var t=du,n=t.observed,r=t.persistentFocus,i=t.autoFocus,o=t.shards,a=t.crossFrame,s=t.focusOptions,l=n||pu&&pu.portaledElement,u=document&&document.activeElement;if(l){var c=[l].concat(o.map(Eu).filter(Boolean));if(u&&!gu(u)||(r||Tu(a)||!cu()||!fu&&i)&&(l&&!(Bl(c)||u&&Cu(u,c)||yu(u))&&(document&&!fu&&u&&!i?(u.blur&&u.blur(),document.body.focus()):(e=su(c,fu,{focusOptions:s}),pu={})),hu=!1,fu=document&&document.activeElement),document){var d=document&&document.activeElement,f=ru(c),p=f.map((function(e){return e.node})).indexOf(d);p>-1&&(f.filter((function(e){var t=e.guard,n=e.node;return t&&n.dataset.focusAutoGuard})).forEach((function(e){return e.node.removeAttribute("tabIndex")})),bu(p,f.length,1,f),bu(p,-1,-1,f))}}}return e}),"activateTrap"),xu=g((function(e){Su()&&e&&(e.stopPropagation(),e.preventDefault())}),"onTrap"),ku=g((function(){return lu(Su)}),"onBlur"),Nu=g((function(e){var t=e.target,n=e.currentTarget;n.contains(t)||vu(n,t)}),"onFocus"),_u=g((function(){return null}),"FocusWatcher"),Ou=g((function(){hu="just",setTimeout((function(){hu="meanwhile"}),0)}),"onWindowBlur"),Iu=g((function(){document.addEventListener("focusin",xu),document.addEventListener("focusout",ku),window.addEventListener("blur",Ou)}),"attachHandler"),Du=g((function(){document.removeEventListener("focusin",xu),document.removeEventListener("focusout",ku),window.removeEventListener("blur",Ou)}),"detachHandler");function Lu(e){return e.filter((function(e){return!e.disabled}))}function Au(e){var t=e.slice(-1)[0];t&&!du&&Iu();var n=du,r=n&&t&&t.id===n.id;du=t,n&&!r&&(n.onDeactivation(),e.filter((function(e){return e.id===n.id})).length||n.returnFocus(!t)),t?(fu=null,r&&n.observed===t.observed||t.onActivation(),Su(),lu(Su)):(Du(),fu=null)}g(Lu,"reducePropsToState"),g(Au,"handleStateChangeOnClient"),zs.assignSyncMedium(Nu),Ws.assignMedium(ku),Ks.assignMedium((function(e){return e({moveFocusInside:su,focusInside:Bl})}));var Mu=nl(Lu,Au)(_u),Ru=t.forwardRef(g((function(e,n){return t.createElement(Js,Ns({sideCar:Mu,ref:n},e))}),"FocusLockUICombination")),Fu=Js.propTypes||{};Fu.sideCar,ks(Fu,["sideCar"]),Ru.propTypes={};var Pu=Ru,ju="right-scroll-bar-position",Vu="width-before-scroll-bar",Uu=qs(),Bu=g((function(){}),"nothing"),$u=t.forwardRef((function(e,n){var r=t.useRef(null),i=t.useState({onScrollCapture:Bu,onWheelCapture:Bu,onTouchMoveCapture:Bu}),o=i[0],a=i[1],s=e.forwardProps,l=e.children,u=e.className,c=e.removeScrollBar,d=e.enabled,f=e.shards,p=e.sideCar,h=e.noIsolation,m=e.inert,g=e.allowPinchZoom,v=e.as,y=void 0===v?"div":v,b=js(e,["forwardProps","children","className","removeScrollBar","enabled","shards","sideCar","noIsolation","inert","allowPinchZoom","as"]),E=p,T=Rs([r,n]),w=Ps(Ps({},b),o);return t.createElement(t.Fragment,null,d&&t.createElement(E,{sideCar:Uu,removeScrollBar:c,shards:f,noIsolation:h,inert:m,setCallbacks:a,allowPinchZoom:!!g,lockRef:r}),s?t.cloneElement(t.Children.only(l),Ps(Ps({},w),{ref:T})):t.createElement(y,Ps({},w,{className:u,ref:T}),l))}));$u.defaultProps={enabled:!0,removeScrollBar:!0,inert:!1},$u.classNames={fullWidth:Vu,zeroRight:ju};var qu=g((function(){return n.nc}),"getNonce");function Hu(){if(!document)return null;var e=document.createElement("style");e.type="text/css";var t=qu();return t&&e.setAttribute("nonce",t),e}function Gu(e,t){e.styleSheet?e.styleSheet.cssText=t:e.appendChild(document.createTextNode(t))}function zu(e){(document.head||document.getElementsByTagName("head")[0]).appendChild(e)}g(Hu,"makeStyleTag"),g(Gu,"injectStyles"),g(zu,"insertStyleTag");var Wu=g((function(){var e=0,t=null;return{add:function(n){0==e&&(t=Hu())&&(Gu(t,n),zu(t)),e++},remove:function(){!--e&&t&&(t.parentNode&&t.parentNode.removeChild(t),t=null)}}}),"stylesheetSingleton"),Ku=g((function(){var e=Wu();return function(n,r){t.useEffect((function(){return e.add(n),function(){e.remove()}}),[n&&r])}}),"styleHookSingleton"),Qu=g((function(){var e=Ku();return g((function(t){var n=t.styles,r=t.dynamic;return e(n,r),null}),"Sheet")}),"styleSingleton"),Xu={left:0,top:0,right:0,gap:0},Yu=g((function(e){return parseInt(e||"",10)||0}),"parse$1"),Ju=g((function(e){var t=window.getComputedStyle(document.body),n=t["padding"===e?"paddingLeft":"marginLeft"],r=t["padding"===e?"paddingTop":"marginTop"],i=t["padding"===e?"paddingRight":"marginRight"];return[Yu(n),Yu(r),Yu(i)]}),"getOffset"),Zu=g((function(e){if(void 0===e&&(e="margin"),"undefined"==typeof window)return Xu;var t=Ju(e),n=document.documentElement.clientWidth,r=window.innerWidth;return{left:t[0],top:t[1],right:t[2],gap:Math.max(0,r-n+t[2]-t[0])}}),"getGapWidth"),ec=Qu(),tc=g((function(e,t,n,r){var i=e.left,o=e.top,a=e.right,s=e.gap;return void 0===n&&(n="margin"),"\n .".concat("with-scroll-bars-hidden"," {\n overflow: hidden ").concat(r,";\n padding-right: ").concat(s,"px ").concat(r,";\n }\n body {\n overflow: hidden ").concat(r,";\n overscroll-behavior: contain;\n ").concat([t&&"position: relative ".concat(r,";"),"margin"===n&&"\n padding-left: ".concat(i,"px;\n padding-top: ").concat(o,"px;\n padding-right: ").concat(a,"px;\n margin-left:0;\n margin-top:0;\n margin-right: ").concat(s,"px ").concat(r,";\n "),"padding"===n&&"padding-right: ".concat(s,"px ").concat(r,";")].filter(Boolean).join(""),"\n }\n \n .").concat(ju," {\n right: ").concat(s,"px ").concat(r,";\n }\n \n .").concat(Vu," {\n margin-right: ").concat(s,"px ").concat(r,";\n }\n \n .").concat(ju," .").concat(ju," {\n right: 0 ").concat(r,";\n }\n \n .").concat(Vu," .").concat(Vu," {\n margin-right: 0 ").concat(r,";\n }\n \n body {\n ").concat("--removed-body-scroll-bar-size",": ").concat(s,"px;\n }\n")}),"getStyles$2"),nc=g((function(e){var n=e.noRelative,r=e.noImportant,i=e.gapMode,o=void 0===i?"margin":i,a=t.useMemo((function(){return Zu(o)}),[o]);return t.createElement(ec,{styles:tc(a,!n,o,r?"":"!important")})}),"RemoveScrollBar"),rc=!1;if("undefined"!=typeof window)try{var ic=Object.defineProperty({},"passive",{get:function(){return rc=!0,!0}});window.addEventListener("test",ic,ic),window.removeEventListener("test",ic,ic)}catch(e){rc=!1}var oc=!!rc&&{passive:!1},ac=g((function(e){return"TEXTAREA"===e.tagName}),"alwaysContainsScroll"),sc=g((function(e,t){var n=window.getComputedStyle(e);return"hidden"!==n[t]&&!(n.overflowY===n.overflowX&&!ac(e)&&"visible"===n[t])}),"elementCanBeScrolled"),lc=g((function(e){return sc(e,"overflowY")}),"elementCouldBeVScrolled"),uc=g((function(e){return sc(e,"overflowX")}),"elementCouldBeHScrolled"),cc=g((function(e,t){var n=t;do{if("undefined"!=typeof ShadowRoot&&n instanceof ShadowRoot&&(n=n.host),pc(e,n)){var r=hc(e,n);if(r[1]>r[2])return!0}n=n.parentNode}while(n&&n!==document.body);return!1}),"locationCouldBeScrolled"),dc=g((function(e){return[e.scrollTop,e.scrollHeight,e.clientHeight]}),"getVScrollVariables"),fc=g((function(e){return[e.scrollLeft,e.scrollWidth,e.clientWidth]}),"getHScrollVariables"),pc=g((function(e,t){return"v"===e?lc(t):uc(t)}),"elementCouldBeScrolled"),hc=g((function(e,t){return"v"===e?dc(t):fc(t)}),"getScrollVariables"),mc=g((function(e,t){return"h"===e&&"rtl"===t?-1:1}),"getDirectionFactor"),gc=g((function(e,t,n,r,i){var o=mc(e,window.getComputedStyle(t).direction),a=o*r,s=n.target,l=t.contains(s),u=!1,c=a>0,d=0,f=0;do{var p=hc(e,s),h=p[0],m=p[1]-p[2]-o*h;(h||m)&&pc(e,s)&&(d+=m,f+=h),s=s.parentNode}while(!l&&s!==document.body||l&&(t.contains(s)||t===s));return(c&&(i&&0===d||!i&&a>d)||!c&&(i&&0===f||!i&&-a>f))&&(u=!0),u}),"handleScroll"),vc=g((function(e){return"changedTouches"in e?[e.changedTouches[0].clientX,e.changedTouches[0].clientY]:[0,0]}),"getTouchXY"),yc=g((function(e){return[e.deltaX,e.deltaY]}),"getDeltaXY"),bc=g((function(e){return e&&"current"in e?e.current:e}),"extractRef"),Ec=g((function(e,t){return e[0]===t[0]&&e[1]===t[1]}),"deltaCompare"),Tc=g((function(e){return"\n .block-interactivity-".concat(e," {pointer-events: none;}\n .allow-interactivity-").concat(e," {pointer-events: all;}\n")}),"generateStyle"),wc=0,Cc=[];function Sc(e){var n=t.useRef([]),r=t.useRef([0,0]),i=t.useRef(),o=t.useState(wc++)[0],a=t.useState((function(){return Qu()}))[0],s=t.useRef(e);t.useEffect((function(){s.current=e}),[e]),t.useEffect((function(){if(e.inert){document.body.classList.add("block-interactivity-".concat(o));var t=Vs([e.lockRef.current],(e.shards||[]).map(bc),!0).filter(Boolean);return t.forEach((function(e){return e.classList.add("allow-interactivity-".concat(o))})),function(){document.body.classList.remove("block-interactivity-".concat(o)),t.forEach((function(e){return e.classList.remove("allow-interactivity-".concat(o))}))}}}),[e.inert,e.lockRef.current,e.shards]);var l=t.useCallback((function(e,t){if("touches"in e&&2===e.touches.length)return!s.current.allowPinchZoom;var n,o=vc(e),a=r.current,l="deltaX"in e?e.deltaX:a[0]-o[0],u="deltaY"in e?e.deltaY:a[1]-o[1],c=e.target,d=Math.abs(l)>Math.abs(u)?"h":"v";if("touches"in e&&"h"===d&&"range"===c.type)return!1;var f=cc(d,c);if(!f)return!0;if(f?n=d:(n="v"===d?"h":"v",f=cc(d,c)),!f)return!1;if(!i.current&&"changedTouches"in e&&(l||u)&&(i.current=n),!n)return!0;var p=i.current||n;return gc(p,t,e,"h"===p?l:u,!0)}),[]),u=t.useCallback((function(e){var t=e;if(Cc.length&&Cc[Cc.length-1]===a){var r="deltaY"in t?yc(t):vc(t),i=n.current.filter((function(e){return e.name===t.type&&e.target===t.target&&Ec(e.delta,r)}))[0];if(i&&i.should)t.cancelable&&t.preventDefault();else if(!i){var o=(s.current.shards||[]).map(bc).filter(Boolean).filter((function(e){return e.contains(t.target)}));(o.length>0?l(t,o[0]):!s.current.noIsolation)&&t.cancelable&&t.preventDefault()}}}),[]),c=t.useCallback((function(e,t,r,i){var o={name:e,delta:t,target:r,should:i};n.current.push(o),setTimeout((function(){n.current=n.current.filter((function(e){return e!==o}))}),1)}),[]),d=t.useCallback((function(e){r.current=vc(e),i.current=void 0}),[]),f=t.useCallback((function(t){c(t.type,yc(t),t.target,l(t,e.lockRef.current))}),[]),p=t.useCallback((function(t){c(t.type,vc(t),t.target,l(t,e.lockRef.current))}),[]);t.useEffect((function(){return Cc.push(a),e.setCallbacks({onScrollCapture:f,onWheelCapture:f,onTouchMoveCapture:p}),document.addEventListener("wheel",u,oc),document.addEventListener("touchmove",u,oc),document.addEventListener("touchstart",d,oc),function(){Cc=Cc.filter((function(e){return e!==a})),document.removeEventListener("wheel",u,oc),document.removeEventListener("touchmove",u,oc),document.removeEventListener("touchstart",d,oc)}}),[]);var h=e.removeScrollBar,m=e.inert;return t.createElement(t.Fragment,null,m?t.createElement(a,{styles:Tc(o)}):null,h?t.createElement(nc,{gapMode:"margin"}):null)}g(Sc,"RemoveScrollSideCar");var xc=Gs(Uu,Sc),kc=t.forwardRef((function(e,n){return t.createElement($u,Ps({},e,{ref:n,sideCar:xc}))}));kc.classNames=$u.classNames;var Nc=kc,_c={exports:{}},Oc="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED";function Ic(){}function Dc(){}g(Ic,"emptyFunction"),g(Dc,"emptyFunctionWithReset"),Dc.resetWarningCache=Ic;var Lc=g((function(){function e(e,t,n,r,i,o){if(o!==Oc){var a=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw a.name="Invariant Violation",a}}function t(){return e}g(e,"shim"),e.isRequired=e,g(t,"getShim");var n={array:e,bigint:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,elementType:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t,checkPropTypes:Dc,resetWarningCache:Ic};return n.PropTypes=n,n}),"factoryWithThrowingShims");_c.exports=Lc();var Ac=_c.exports;function Mc(){return Mc=Object.assign||function(e){for(var t=1;t=0||(i[n]=e[n]);return i}g(Mc,"_extends$9"),g(Rc,"_objectWithoutPropertiesLoose$9");var Fc=["as","isOpen"],Pc=["allowPinchZoom","as","dangerouslyBypassFocusLock","dangerouslyBypassScrollLock","initialFocusRef","onClick","onDismiss","onKeyDown","onMouseDown","unstable_lockFocusAcrossFrames"],jc=["as","onClick","onKeyDown"],Vc=["allowPinchZoom","initialFocusRef","isOpen","onDismiss"];Ac.bool,Ac.bool,Ac.bool,Ac.func;var Uc=(0,t.forwardRef)(g((function(e,n){var r=e.as,i=void 0===r?"div":r,o=e.isOpen,a=void 0===o||o,s=Rc(e,Fc);return(0,t.useEffect)((function(){a?window.__REACH_DISABLE_TOOLTIPS=!0:window.requestAnimationFrame((function(){window.__REACH_DISABLE_TOOLTIPS=!1}))}),[a]),a?(0,t.createElement)(hs,{"data-reach-dialog-wrapper":""},(0,t.createElement)(Bc,Mc({ref:n,as:i},s))):null}),"DialogOverlay")),Bc=(0,t.forwardRef)(g((function(e,n){var r=e.allowPinchZoom,i=e.as,o=void 0===i?"div":i,a=e.dangerouslyBypassFocusLock,s=void 0!==a&&a,l=e.dangerouslyBypassScrollLock,u=void 0!==l&&l,c=e.initialFocusRef,d=e.onClick,f=e.onDismiss,p=void 0===f?bs:f,h=e.onKeyDown,m=e.onMouseDown,v=e.unstable_lockFocusAcrossFrames,y=Rc(e,Pc),b=(0,t.useRef)(null),E=(0,t.useRef)(null),T=Ss(E,n),w=(0,t.useCallback)((function(){c&&c.current&&c.current.focus()}),[c]);function C(e){b.current===e.target&&(e.stopPropagation(),p(e))}function S(e){"Escape"===e.key&&(e.stopPropagation(),p(e))}function x(e){b.current=e.target}return g(C,"handleClick"),g(S,"handleKeyDown"),g(x,"handleMouseDown"),(0,t.useEffect)((function(){return E.current?Hc(E.current):void 0}),[]),(0,t.createElement)(Pu,{autoFocus:!0,returnFocus:!0,onActivation:w,disabled:s,crossFrame:null==v||v},(0,t.createElement)(Nc,{allowPinchZoom:r,enabled:!u},(0,t.createElement)(o,Mc({},y,{ref:T,"data-reach-dialog-overlay":"",onClick:xs(d,C),onKeyDown:xs(h,S),onMouseDown:xs(m,x)}))))}),"DialogInner")),$c=(0,t.forwardRef)(g((function(e,n){var r=e.as,i=void 0===r?"div":r,o=e.onClick;e.onKeyDown;var a=Rc(e,jc);return(0,t.createElement)(i,Mc({"aria-modal":"true",role:"dialog",tabIndex:-1},a,{ref:n,"data-reach-dialog-content":"",onClick:xs(o,(function(e){e.stopPropagation()}))}))}),"DialogContent")),qc=(0,t.forwardRef)(g((function(e,n){var r=e.allowPinchZoom,i=void 0!==r&&r,o=e.initialFocusRef,a=e.isOpen,s=e.onDismiss,l=void 0===s?bs:s,u=Rc(e,Vc);return(0,t.createElement)(Uc,{allowPinchZoom:i,initialFocusRef:o,isOpen:a,onDismiss:l},(0,t.createElement)($c,Mc({ref:n},u)))}),"Dialog"));function Hc(e){var t=[],n=[],r=ms(e);return e?(Array.prototype.forEach.call(r.querySelectorAll("body > *"),(function(r){var i,o;if(r!==(null==(i=e.parentNode)||null==(o=i.parentNode)?void 0:o.parentNode)){var a=r.getAttribute("aria-hidden");null!==a&&"false"!==a||(t.push(a),n.push(r),r.setAttribute("aria-hidden","true"))}})),function(){n.forEach((function(e,n){var r=t[n];null===r?e.removeAttribute("aria-hidden"):e.setAttribute("aria-hidden",r)}))}):bs}function Gc(){return Gc=Object.assign||function(e){for(var t=1;t=0||(i[n]=e[n]);return i}g(Hc,"createAriaHider"),g(Gc,"_extends$8"),g(zc,"_objectWithoutPropertiesLoose$8");var Wc=["as","style"],Kc=(0,t.forwardRef)(g((function(e,n){var r=e.as,i=void 0===r?"span":r,o=e.style,a=void 0===o?{}:o,s=zc(e,Wc);return(0,t.createElement)(i,Gc({ref:n,style:Gc({border:0,clip:"rect(0 0 0 0)",height:"1px",margin:"-1px",overflow:"hidden",padding:0,position:"absolute",width:"1px",whiteSpace:"nowrap",wordWrap:"normal"},a)},s))}),"VisuallyHidden")),Qc=Object.defineProperty;const Xc=g(((e,t)=>Qc(e,"name",{value:t,configurable:!0})),"__name$D")(((e,t)=>Object.entries(t).reduce(((e,t)=>{let[n,r]=t;return e[n]=r,e}),e)),"createComponentGroup"),Yc=(0,t.forwardRef)(((e,t)=>de(qc,m(h({},e),{ref:t}))));Yc.displayName="Dialog";const Jc=(0,t.forwardRef)(((e,t)=>fe(os,m(h({},e),{ref:t,type:"button",className:b("graphiql-dialog-close",e.className),children:[de(Kc,{children:"Close dialog"}),de(La,{})]}))));Jc.displayName="Dialog.Close";const Zc=Xc(Yc,{Close:Jc});e.aJ=Zc;var ed=!1,td=0;function nd(){return++td}function rd(e){var n;if("function"==typeof t.useId){var r=(0,t.useId)(e);return null!=e?e:r}var i=null!=e?e:ed?nd():null,o=(0,t.useState)(i),a=o[0],s=o[1];return us((function(){null===a&&s(nd())}),[]),(0,t.useEffect)((function(){!1===ed&&(ed=!0)}),[]),null!=(n=null!=e?e:a)?n:void 0}g(nd,"genId"),g(rd,"useId");var id,od=["bottom","height","left","right","top","width"],ad=g((function(e,t){return void 0===e&&(e={}),void 0===t&&(t={}),od.some((function(n){return e[n]!==t[n]}))}),"rectChanged"),sd=new Map,ld=g((function e(){var t=[];sd.forEach((function(e,n){var r=n.getBoundingClientRect();ad(r,e.rect)&&(e.rect=r,t.push(e))})),t.forEach((function(e){e.callbacks.forEach((function(t){return t(e.rect)}))})),id=window.requestAnimationFrame(e)}),"run");function ud(e,t){return{observe:g((function(){var n=0===sd.size;sd.has(e)?sd.get(e).callbacks.push(t):sd.set(e,{rect:void 0,hasRectChanged:!1,callbacks:[t]}),n&&ld()}),"observe"),unobserve:g((function(){var n=sd.get(e);if(n){var r=n.callbacks.indexOf(t);r>=0&&n.callbacks.splice(r,1),n.callbacks.length||sd.delete(e),sd.size||cancelAnimationFrame(id)}}),"unobserve")}}function cd(e,n,r){var i,o,a;gs(n)?i=n:(i=null==(a=null==n?void 0:n.observe)||a,o=null==n?void 0:n.onChange),vs(r)&&(o=r);var s=(0,t.useState)(e.current),l=s[0],u=s[1],c=(0,t.useRef)(!1),d=(0,t.useRef)(!1),f=(0,t.useState)(null),p=f[0],h=f[1],m=(0,t.useRef)(o);return us((function(){m.current=o,e.current!==l&&u(e.current)})),us((function(){l&&!c.current&&(c.current=!0,h(l.getBoundingClientRect()))}),[l]),us((function(){if(i){var t=l;if(d.current||(d.current=!0,t=e.current),t){var n=ud(t,(function(e){null==m.current||m.current(e),h(e)}));return n.observe(),function(){n.unobserve()}}}}),[i,l,e]),p}g(ud,"observeRect"),g(cd,"useRect");var dd=["input","select","textarea","a[href]","button","[tabindex]","audio[controls]","video[controls]",'[contenteditable]:not([contenteditable="false"])'],fd=dd.join(","),pd="undefined"==typeof Element?function(){}:Element.prototype.matches||Element.prototype.msMatchesSelector||Element.prototype.webkitMatchesSelector;function hd(e,t){t=t||{};var n,r,i,o=[],a=[],s=e.querySelectorAll(fd);for(t.includeContainer&&pd.call(e,fd)&&(s=Array.prototype.slice.apply(s)).unshift(e),n=0;n=0||(i[n]=e[n]);return i}g(Dd,"_extends$7"),g(Ld,"_objectWithoutPropertiesLoose$7");var Ad=["unstable_skipInitialPortalRender"],Md=["as","targetRef","position","unstable_observableRefs"],Rd=(0,t.forwardRef)(g((function(e,n){var r=e.unstable_skipInitialPortalRender,i=Ld(e,Ad);return(0,t.createElement)(hs,{unstable_skipInitialRender:r},(0,t.createElement)(Fd,Dd({ref:n},i)))}),"Popover")),Fd=(0,t.forwardRef)(g((function(e,n){var r=e.as,i=void 0===r?"div":r,o=e.targetRef,a=e.position,s=void 0===a?Vd:a,l=e.unstable_observableRefs,u=void 0===l?[]:l,c=Ld(e,Md),d=(0,t.useRef)(null),f=cd(d,{observe:!c.hidden}),p=cd(o,{observe:!c.hidden}),h=Ss(d,n);return $d(o,d),(0,t.createElement)(i,Dd({"data-reach-popover":"",ref:h},c,{style:Dd({position:"absolute"},Pd.apply(void 0,[s,p,f].concat(u)),c.style)}))}),"PopoverImpl"));function Pd(e,t,n){for(var r=arguments.length,i=new Array(r>3?r-3:0),o=3;o=0||(i[n]=e[n]);return i}function Hd(){return Hd=Object.assign||function(e){for(var t=1;t=0||(i[n]=e[n]);return i}g(zd,"createDescendantContext"),g(Wd,"useDescendant"),g(Kd,"useDescendantsInit"),g(Qd,"useDescendants"),g(Xd,"DescendantProvider"),g(Yd,"useDescendantKeyDown"),g(Jd,"isRightClick"),g(Zd,"createStableCallbackHook"),g(ef,"useStableCallback"),g(tf,"_objectWithoutPropertiesLoose$5");var nf,rf,of=["children"];function af(e,n){return(0,t.createContext)(n)}function sf(e,n){var r=(0,t.createContext)(n);function i(e){var n=e.children,i=tf(e,of),o=(0,t.useMemo)((function(){return i}),Object.values(i));return(0,t.createElement)(r.Provider,{value:o},n)}function o(i){var o=(0,t.useContext)(r);if(o)return o;if(n)return n;throw Error(i+" must be rendered inside of a "+e+" component.")}return g(i,"Provider"),g(o,"useContext$1"),[i,o]}function lf(){for(var e=arguments.length,t=new Array(e),n=0;n0||m,matches:hf(o)}}}}),"x");try{for(var p=function(e){var t="function"==typeof Symbol&&e[Symbol.iterator],n=0;return t?t.call(e):{next:function(){return e&&n>=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}}}(d),h=p.next();!h.done;h=p.next()){var m=f(h.value);if("object"==typeof m)return m.value}}catch(e){i={error:e}}finally{try{h&&!h.done&&(o=p.return)&&o.call(p)}finally{if(i)throw i.error}}}return gf(s,l)}};return n}g(df,"e$1"),g(ff,"r$1"),g(pf,"i$1"),g(hf,"o"),g(mf,"a"),g(gf,"u"),g(vf,"c$1");var yf=g((function(e,t){return e.actions.forEach((function(n){var r=n.exec;return r&&r(e.context,t)}))}),"s");function bf(e){var t=e.initialState,n=nf.NotStarted,r=new Set,i={_machine:e,send:function(i){n===nf.Running&&(t=e.transition(t,i),yf(t,mf(i)),r.forEach((function(e){return e(t)})))},subscribe:function(e){return r.add(e),e(t),{unsubscribe:function(){return r.delete(e)}}},start:function(){return n=nf.Running,yf(t,cf),i},stop:function(){return n=nf.Stopped,r.clear(),i},get state(){return t},get status(){return n}};return i}function Ef(e){var n=(0,t.useRef)();return n.current||(n.current={v:e()}),n.current.v}function Tf(){return Tf=Object.assign||function(e){for(var t=1;t=0||(i[n]=e[n]);return i}g(_f,"useMachine"),g(Of,"unwrapRefs"),g(If,"useCreateMachine"),g(Df,"_extends$4"),g(Lf,"_objectWithoutPropertiesLoose$4"),(kf=Cf||(Cf={})).Idle="IDLE",kf.Open="OPEN",kf.Navigating="NAVIGATING",kf.Dragging="DRAGGING",kf.Interacting="INTERACTING",(xf=Sf||(Sf={})).ButtonMouseDown="BUTTON_MOUSE_DOWN",xf.ButtonMouseUp="BUTTON_MOUSE_UP",xf.Blur="BLUR",xf.ClearNavSelection="CLEAR_NAV_SELECTION",xf.ClearTypeahead="CLEAR_TYPEAHEAD",xf.GetDerivedData="GET_DERIVED_DATA",xf.KeyDownEscape="KEY_DOWN_ESCAPE",xf.KeyDownEnter="KEY_DOWN_ENTER",xf.KeyDownSpace="KEY_DOWN_SPACE",xf.KeyDownNavigate="KEY_DOWN_NAVIGATE",xf.KeyDownSearch="KEY_DOWN_SEARCH",xf.KeyDownTab="KEY_DOWN_TAB",xf.KeyDownShiftTab="KEY_DOWN_SHIFT_TAB",xf.OptionTouchStart="OPTION_TOUCH_START",xf.OptionMouseMove="OPTION_MOUSE_MOVE",xf.OptionMouseEnter="OPTION_MOUSE_ENTER",xf.OptionMouseDown="OPTION_MOUSE_DOWN",xf.OptionMouseUp="OPTION_MOUSE_UP",xf.OptionClick="OPTION_CLICK",xf.ListMouseUp="LIST_MOUSE_UP",xf.OptionPress="OPTION_PRESS",xf.OutsideMouseDown="OUTSIDE_MOUSE_DOWN",xf.OutsideMouseUp="OUTSIDE_MOUSE_UP",xf.ValueChange="VALUE_CHANGE",xf.PopoverPointerDown="POPOVER_POINTER_DOWN",xf.PopoverPointerUp="POPOVER_POINTER_UP",xf.UpdateAfterTypeahead="UPDATE_AFTER_TYPEAHEAD";var Af=ff({navigationValue:null}),Mf=ff({typeaheadQuery:null}),Rf=ff({value:g((function(e,t){return t.value}),"value")}),Ff=ff({navigationValue:g((function(e,t){return t.value}),"navigationValue")}),Pf=ff({navigationValue:g((function(e){var t,n=tp(e.value,e.options);return n&&!n.disabled?e.value:(null==(t=e.options.find((function(e){return!e.disabled})))?void 0:t.value)||null}),"navigationValue")});function jf(e,t){if(t.type===Sf.Blur){var n=t.refs,r=n.list,i=n.popover,o=t.relatedTarget,a=ms(i);return!((null==a?void 0:a.activeElement)===r||!i||i.contains(o||(null==a?void 0:a.activeElement)))}return!1}function Vf(e,t){if(t.type===Sf.OutsideMouseDown||t.type===Sf.OutsideMouseUp){var n=t.refs,r=n.button,i=n.popover,o=t.relatedTarget;return!(o===r||!r||r.contains(o)||!i||i.contains(o))}return!1}function Uf(e,t){return!!e.options.find((function(t){return t.value===e.navigationValue}))}function Bf(e,t){var n=t.refs,r=n.popover,i=n.list,o=t.relatedTarget;return!(r&&o&&r.contains(o)&&o!==i)&&Uf(e)}function $f(e,t){requestAnimationFrame((function(){t.refs.list&&t.refs.list.focus()}))}function qf(e,t){t.refs.button&&t.refs.button.focus()}function Hf(e,t){return!t.disabled}function Gf(e,t){return t.type!==Sf.OptionTouchStart||!t||!t.disabled}function zf(e,t){return!("disabled"in t&&t.disabled||("value"in t?null==t.value:null==e.navigationValue))}function Wf(e,t){t.callback&&t.callback(t.value)}function Kf(e,t){if(t.type===Sf.KeyDownEnter){var n=t.refs.hiddenInput;if(n&&n.form){var r=n.form.querySelector("button:not([type]),[type='submit']");r&&r.click()}}}g(jf,"listboxLostFocus"),g(Vf,"clickedOutsideOfListbox"),g(Uf,"optionIsActive"),g(Bf,"shouldNavigate"),g($f,"focusList"),g(qf,"focusButton"),g(Hf,"listboxIsNotDisabled"),g(Gf,"optionIsNavigable"),g(zf,"optionIsSelectable"),g(Wf,"selectOption"),g(Kf,"submitForm");var Qf=ff({typeaheadQuery:g((function(e,t){return(e.typeaheadQuery||"")+t.query}),"typeaheadQuery")}),Xf=ff({value:g((function(e,t){if(t.type===Sf.UpdateAfterTypeahead&&t.query){var n=ep(e.options,t.query);if(n&&!n.disabled)return t.callback&&t.callback(n.value),n.value}return e.value}),"value")}),Yf=ff({navigationValue:g((function(e,t){if(t.type===Sf.UpdateAfterTypeahead&&t.query){var n=ep(e.options,t.query);if(n&&!n.disabled)return n.value}return e.navigationValue}),"navigationValue")}),Jf=((wf={})[Sf.GetDerivedData]={actions:ff((function(e,t){return Df({},e,t.data)}))},wf[Sf.ValueChange]={actions:[Rf,Wf]},wf),Zf=g((function(e){var t,n,r,i,o,a,s=e.value;return{id:"listbox",initial:Cf.Idle,context:{value:s,options:[],navigationValue:null,typeaheadQuery:null},states:(a={},a[Cf.Idle]={on:Df({},Jf,(t={},t[Sf.ButtonMouseDown]={target:Cf.Open,actions:[Pf],cond:Hf},t[Sf.KeyDownSpace]={target:Cf.Navigating,actions:[Pf,$f],cond:Hf},t[Sf.KeyDownSearch]={target:Cf.Idle,actions:Qf,cond:Hf},t[Sf.UpdateAfterTypeahead]={target:Cf.Idle,actions:[Xf],cond:Hf},t[Sf.ClearTypeahead]={target:Cf.Idle,actions:Mf},t[Sf.KeyDownNavigate]={target:Cf.Navigating,actions:[Pf,Mf,$f],cond:Hf},t[Sf.KeyDownEnter]={actions:[Kf],cond:Hf},t))},a[Cf.Interacting]={entry:[Af],on:Df({},Jf,(n={},n[Sf.ClearNavSelection]={actions:[Af,$f]},n[Sf.KeyDownEnter]={target:Cf.Idle,actions:[Rf,Mf,qf,Wf],cond:zf},n[Sf.KeyDownSpace]={target:Cf.Idle,actions:[Rf,Mf,qf,Wf],cond:zf},n[Sf.ButtonMouseDown]={target:Cf.Idle,actions:[qf]},n[Sf.KeyDownEscape]={target:Cf.Idle,actions:[qf]},n[Sf.OptionMouseDown]={target:Cf.Dragging},n[Sf.OutsideMouseDown]=[{target:Cf.Idle,cond:Vf,actions:Mf},{target:Cf.Dragging,actions:Mf,cond:Uf}],n[Sf.OutsideMouseUp]=[{target:Cf.Idle,cond:Vf,actions:Mf},{target:Cf.Navigating,cond:Uf},{target:Cf.Interacting,actions:Mf}],n[Sf.KeyDownEnter]=Cf.Interacting,n[Sf.Blur]=[{target:Cf.Idle,cond:jf,actions:Mf},{target:Cf.Navigating,cond:Bf},{target:Cf.Interacting,actions:Mf}],n[Sf.OptionTouchStart]={target:Cf.Navigating,actions:[Ff,Mf],cond:Gf},n[Sf.OptionClick]={target:Cf.Idle,actions:[Rf,Mf,qf,Wf],cond:zf},n[Sf.OptionPress]={target:Cf.Idle,actions:[Rf,Mf,qf,Wf],cond:zf},n[Sf.OptionMouseEnter]={target:Cf.Navigating,actions:[Ff,Mf],cond:Gf},n[Sf.KeyDownNavigate]={target:Cf.Navigating,actions:[Ff,Mf,$f]},n))},a[Cf.Open]={on:Df({},Jf,(r={},r[Sf.ClearNavSelection]={actions:[Af]},r[Sf.KeyDownEnter]={target:Cf.Idle,actions:[Rf,Mf,qf,Wf],cond:zf},r[Sf.KeyDownSpace]={target:Cf.Idle,actions:[Rf,Mf,qf,Wf],cond:zf},r[Sf.ButtonMouseDown]={target:Cf.Idle,actions:[qf]},r[Sf.KeyDownEscape]={target:Cf.Idle,actions:[qf]},r[Sf.OptionMouseDown]={target:Cf.Dragging},r[Sf.OutsideMouseDown]=[{target:Cf.Idle,cond:Vf,actions:Mf},{target:Cf.Dragging,cond:Uf},{target:Cf.Interacting,actions:Mf}],r[Sf.OutsideMouseUp]=[{target:Cf.Idle,cond:Vf,actions:Mf},{target:Cf.Navigating,cond:Uf},{target:Cf.Interacting,actions:Mf}],r[Sf.Blur]=[{target:Cf.Idle,cond:jf,actions:Mf},{target:Cf.Navigating,cond:Bf},{target:Cf.Interacting,actions:Mf}],r[Sf.ButtonMouseUp]={target:Cf.Navigating,actions:[Pf,$f]},r[Sf.ListMouseUp]={target:Cf.Navigating,actions:[Pf,$f]},r[Sf.OptionTouchStart]={target:Cf.Navigating,actions:[Ff,Mf],cond:Gf},r[Sf.OptionClick]={target:Cf.Idle,actions:[Rf,Mf,qf,Wf],cond:zf},r[Sf.OptionPress]={target:Cf.Idle,actions:[Rf,Mf,qf,Wf],cond:zf},r[Sf.KeyDownNavigate]={target:Cf.Navigating,actions:[Ff,Mf,$f]},r[Sf.KeyDownSearch]={target:Cf.Navigating,actions:Qf},r[Sf.UpdateAfterTypeahead]={actions:[Yf]},r[Sf.ClearTypeahead]={actions:Mf},r[Sf.OptionMouseMove]=[{target:Cf.Dragging,actions:[Ff],cond:Gf},{target:Cf.Dragging}],r))},a[Cf.Dragging]={on:Df({},Jf,(i={},i[Sf.ClearNavSelection]={actions:[Af]},i[Sf.KeyDownEnter]={target:Cf.Idle,actions:[Rf,Mf,qf,Wf],cond:zf},i[Sf.KeyDownSpace]={target:Cf.Idle,actions:[Rf,Mf,qf,Wf],cond:zf},i[Sf.ButtonMouseDown]={target:Cf.Idle,actions:[qf]},i[Sf.KeyDownEscape]={target:Cf.Idle,actions:[qf]},i[Sf.OptionMouseDown]={target:Cf.Dragging},i[Sf.OutsideMouseDown]=[{target:Cf.Idle,cond:Vf,actions:Mf},{target:Cf.Navigating,cond:Uf},{target:Cf.Interacting,actions:Mf}],i[Sf.OutsideMouseUp]=[{target:Cf.Idle,cond:Vf,actions:Mf},{target:Cf.Navigating,cond:Uf,actions:$f},{target:Cf.Interacting,actions:[Mf,$f]}],i[Sf.Blur]=[{target:Cf.Idle,cond:jf,actions:Mf},{target:Cf.Navigating,cond:Bf},{target:Cf.Interacting,actions:Mf}],i[Sf.ButtonMouseUp]={target:Cf.Navigating,actions:[Pf,$f]},i[Sf.OptionTouchStart]={target:Cf.Navigating,actions:[Ff,Mf],cond:Gf},i[Sf.OptionClick]={target:Cf.Idle,actions:[Rf,Mf,qf,Wf],cond:zf},i[Sf.OptionPress]={target:Cf.Idle,actions:[Rf,Mf,qf,Wf],cond:zf},i[Sf.OptionMouseEnter]={target:Cf.Dragging,actions:[Ff,Mf],cond:Gf},i[Sf.KeyDownNavigate]={target:Cf.Navigating,actions:[Ff,Mf,$f]},i[Sf.KeyDownSearch]={target:Cf.Navigating,actions:Qf},i[Sf.UpdateAfterTypeahead]={actions:[Yf]},i[Sf.ClearTypeahead]={actions:Mf},i[Sf.OptionMouseMove]=[{target:Cf.Navigating,actions:[Ff],cond:Gf},{target:Cf.Navigating}],i[Sf.OptionMouseUp]={target:Cf.Idle,actions:[Rf,Mf,qf,Wf],cond:zf},i))},a[Cf.Navigating]={on:Df({},Jf,(o={},o[Sf.ClearNavSelection]={actions:[Af,$f]},o[Sf.KeyDownEnter]={target:Cf.Idle,actions:[Rf,Mf,qf,Wf],cond:zf},o[Sf.KeyDownSpace]={target:Cf.Idle,actions:[Rf,Mf,qf,Wf],cond:zf},o[Sf.ButtonMouseDown]={target:Cf.Idle,actions:[qf]},o[Sf.KeyDownEscape]={target:Cf.Idle,actions:[qf]},o[Sf.OptionMouseDown]={target:Cf.Dragging},o[Sf.OutsideMouseDown]=[{target:Cf.Idle,cond:Vf,actions:Mf},{target:Cf.Navigating,cond:Uf},{target:Cf.Interacting,actions:Mf}],o[Sf.OutsideMouseUp]=[{target:Cf.Idle,cond:Vf,actions:Mf},{target:Cf.Navigating,cond:Uf},{target:Cf.Interacting,actions:Mf}],o[Sf.Blur]=[{target:Cf.Idle,cond:jf,actions:Mf},{target:Cf.Navigating,cond:Bf},{target:Cf.Interacting,actions:Mf}],o[Sf.ButtonMouseUp]={target:Cf.Navigating,actions:[Pf,$f]},o[Sf.OptionTouchStart]={target:Cf.Navigating,actions:[Ff,Mf],cond:Gf},o[Sf.OptionClick]={target:Cf.Idle,actions:[Rf,Mf,qf,Wf],cond:zf},o[Sf.OptionPress]={target:Cf.Idle,actions:[Rf,Mf,qf,Wf],cond:zf},o[Sf.OptionMouseEnter]={target:Cf.Navigating,actions:[Ff,Mf],cond:Gf},o[Sf.KeyDownNavigate]={target:Cf.Navigating,actions:[Ff,Mf,$f]},o[Sf.KeyDownSearch]={target:Cf.Navigating,actions:Qf},o[Sf.UpdateAfterTypeahead]={actions:[Yf]},o[Sf.ClearTypeahead]={actions:Mf},o[Sf.OptionMouseMove]=[{target:Cf.Navigating,actions:[Ff],cond:Gf},{target:Cf.Navigating}],o))},a)}}),"createMachineDefinition");function ep(e,t){return void 0===t&&(t=""),t&&e.find((function(e){return!e.disabled&&e.label&&e.label.toLowerCase().startsWith(t.toLowerCase())}))||null}function tp(e,t){return e?t.find((function(t){return t.value===e})):void 0}g(ep,"findOptionFromTypeahead"),g(tp,"findOptionFromValue");var np=["as","aria-labelledby","aria-label","children","defaultValue","disabled","form","name","onChange","required","value","__componentName"],rp=["arrow","button","children","portal"],ip=["aria-label","arrow","as","children","onKeyDown","onMouseDown","onMouseUp"],op=["as","children"],ap=["as","position","onBlur","onKeyDown","onMouseUp","portal","unstable_observableRefs"],sp=["as"],lp=["as","children","disabled","index","label","onClick","onMouseDown","onMouseEnter","onMouseLeave","onMouseMove","onMouseUp","onTouchStart","value"],up=zd(),cp=af(0,{}),dp=(0,t.forwardRef)(g((function(e,n){var r=e.as,i=void 0===r?"div":r,o=e["aria-labelledby"],a=e["aria-label"],s=e.children,l=e.defaultValue,u=e.disabled,c=void 0!==u&&u,d=e.form,f=e.name,p=e.onChange,h=e.required,m=e.value;e.__componentName;var v=Lf(e,np),y=(0,t.useRef)(null!=m),b=Kd(),E=b[0],T=b[1],w=(0,t.useRef)(null),C=(0,t.useRef)(null),S=(0,t.useRef)(null),x=(0,t.useRef)(null),k=(0,t.useRef)(null),N=(0,t.useRef)(null),_=(0,t.useRef)(null),O=_f(If(Zf({value:(y.current?m:l)||null})),{button:w,hiddenInput:C,highlightedOption:S,input:x,list:k,popover:N,selectedOption:_},false),I=O[0],D=O[1];function L(e){e!==I.context.value&&(null==p||p(e))}g(L,"handleValueChange");var A=rd(v.id),M=v.id||lf("listbox-input",A),R=Ss(x,n),F=(0,t.useMemo)((function(){var e=E.find((function(e){return e.value===I.context.value}));return e?e.label:null}),[E,I.context.value]),P=Tp(I.value),j={ariaLabel:a,ariaLabelledBy:o,buttonRef:w,disabled:c,highlightedOptionRef:S,isExpanded:P,listboxId:M,listboxValueLabel:F,listRef:k,onValueChange:L,popoverRef:N,selectedOptionRef:_,send:D,state:I.value,stateData:I.context},V=(0,t.useRef)(!1);if(!y.current&&null==l&&!V.current&&E.length){V.current=!0;var U=E.find((function(e){return!e.disabled}));U&&U.value&&D({type:Sf.ValueChange,value:U.value})}return xp(m,I.context.value,(function(){D({type:Sf.ValueChange,value:m})})),us((function(){D({type:Sf.GetDerivedData,data:{options:E}})}),[E,D]),(0,t.useEffect)((function(){function e(e){var t=e.target,n=e.relatedTarget;Sp(N.current,t)||D({type:Sf.OutsideMouseDown,relatedTarget:n||t})}return g(e,"handleMouseDown"),P&&window.addEventListener("mousedown",e),function(){window.removeEventListener("mousedown",e)}}),[D,P]),(0,t.useEffect)((function(){function e(e){var t=e.target,n=e.relatedTarget;Sp(N.current,t)||D({type:Sf.OutsideMouseUp,relatedTarget:n||t})}return g(e,"handleMouseUp"),P&&window.addEventListener("mouseup",e),function(){window.removeEventListener("mouseup",e)}}),[D,P]),(0,t.createElement)(i,Df({},v,{ref:R,"data-reach-listbox-input":"","data-state":P?"expanded":"closed","data-value":I.context.value,id:M}),(0,t.createElement)(cp.Provider,{value:j},(0,t.createElement)(Xd,{context:up,items:E,set:T},vs(s)?s({id:M,isExpanded:P,value:I.context.value,selectedOptionRef:_,highlightedOptionRef:S,valueLabel:F,expanded:P}):s,(d||f||h)&&(0,t.createElement)("input",{ref:C,"data-reach-listbox-hidden-input":"",disabled:c,form:d,name:f,readOnly:!0,required:h,tabIndex:-1,type:"hidden",value:I.context.value||""}))))}),"ListboxInput")),fp=(0,t.forwardRef)(g((function(e,n){var r=e.arrow,i=void 0===r?"▼":r,o=e.button,a=e.children,s=e.portal,l=void 0===s||s,u=Lf(e,rp);return(0,t.createElement)(dp,Df({},u,{__componentName:"Listbox",ref:n}),(function(e){var n=e.value,r=e.valueLabel;return(0,t.createElement)(t.Fragment,null,(0,t.createElement)(hp,{arrow:i,children:o?vs(o)?o({value:n,label:r}):o:void 0}),(0,t.createElement)(yp,{portal:l},(0,t.createElement)(bp,null,a)))}))}),"Listbox")),pp=(0,t.forwardRef)(g((function(e,n){var r=e["aria-label"],i=e.arrow,o=void 0!==i&&i,a=e.as,s=void 0===a?"span":a,l=e.children,u=e.onKeyDown,c=e.onMouseDown,d=e.onMouseUp,f=Lf(e,ip),p=(0,t.useContext)(cp),h=p.buttonRef,m=p.send,v=p.ariaLabelledBy,y=p.disabled,b=p.isExpanded,E=p.listboxId,T=p.stateData,w=p.listboxValueLabel,C=T.value,S=Ss(h,n),x=wp();function k(e){Jd(e.nativeEvent)||(e.preventDefault(),e.stopPropagation(),m({type:Sf.ButtonMouseDown,disabled:y}))}function N(e){Jd(e.nativeEvent)||(e.preventDefault(),e.stopPropagation(),m({type:Sf.ButtonMouseUp}))}g(k,"handleMouseDown"),g(N,"handleMouseUp");var _=lf("button",E),O=(0,t.useMemo)((function(){return l?vs(l)?l({isExpanded:b,label:w,value:C,expanded:b}):l:w}),[l,w,b,C]);return(0,t.createElement)(s,Df({"aria-disabled":y||void 0,"aria-expanded":b||void 0,"aria-haspopup":"listbox","aria-labelledby":r?void 0:[v,_].filter(Boolean).join(" "),"aria-label":r,role:"button",tabIndex:y?-1:0},f,{ref:S,"data-reach-listbox-button":"",id:_,onKeyDown:xs(u,x),onMouseDown:xs(c,k),onMouseUp:xs(d,N)}),O,o&&(0,t.createElement)(gp,null,gs(o)?null:o))}),"ListboxButton")),hp=(0,t.memo)(pp),mp=(0,t.forwardRef)(g((function(e,n){var r=e.as,i=void 0===r?"span":r,o=e.children,a=Lf(e,op),s=(0,t.useContext)(cp).isExpanded;return(0,t.createElement)(i,Df({"aria-hidden":!0},a,{ref:n,"data-reach-listbox-arrow":"","data-expanded":s?"":void 0}),vs(o)?o({isExpanded:s,expanded:s}):o||"▼")}),"ListboxArrow")),gp=(0,t.memo)(mp),vp=(0,t.forwardRef)(g((function(e,n){var r=e.as,i=void 0===r?"div":r,o=e.position,a=void 0===o?Ud:o,s=e.onBlur,l=e.onKeyDown,u=e.onMouseUp,c=e.portal,d=void 0===c||c,f=e.unstable_observableRefs,p=Lf(e,ap),h=(0,t.useContext)(cp),m=h.isExpanded,v=h.buttonRef,y=h.popoverRef,b=h.send,E=Ss(y,n),T=wp();function w(){b({type:Sf.ListMouseUp})}g(w,"handleMouseUp");var C=Df({hidden:!m,tabIndex:-1},p,{ref:E,"data-reach-listbox-popover":"",onMouseUp:xs(u,w),onBlur:xs(s,S),onKeyDown:xs(l,T)});function S(e){var t=e.nativeEvent;requestAnimationFrame((function(){b({type:Sf.Blur,relatedTarget:t.relatedTarget||t.target})}))}return g(S,"handleBlur"),d?(0,t.createElement)(Rd,Df({},C,{as:i,targetRef:v,position:a,unstable_observableRefs:f,unstable_skipInitialPortalRender:!0})):(0,t.createElement)(i,C)}),"ListboxPopover")),yp=(0,t.memo)(vp),bp=(0,t.forwardRef)(g((function(e,n){var r=e.as,i=void 0===r?"ul":r,o=Lf(e,sp),a=(0,t.useContext)(cp),s=a.listRef,l=a.ariaLabel,u=a.ariaLabelledBy,c=a.isExpanded,d=a.listboxId,f=a.stateData,p=f.value,h=f.navigationValue,m=Ss(n,s);return(0,t.createElement)(i,Df({"aria-activedescendant":Cp(c?h:p),"aria-labelledby":l?void 0:u,"aria-label":l,role:"listbox",tabIndex:-1},o,{ref:m,"data-reach-listbox-list":"",id:lf("listbox",d)}))}),"ListboxList")),Ep=(0,t.forwardRef)(g((function(e,n){var r=e.as,i=void 0===r?"li":r,o=e.children,a=e.disabled,s=e.index,l=e.label,u=e.onClick,c=e.onMouseDown,d=e.onMouseEnter,f=e.onMouseLeave,p=e.onMouseMove,h=e.onMouseUp,m=e.onTouchStart,v=e.value,y=Lf(e,lp),b=(0,t.useContext)(cp),E=b.highlightedOptionRef,T=b.selectedOptionRef,w=b.send,C=b.isExpanded,S=b.onValueChange,x=b.state,k=b.stateData,N=k.value,_=k.navigationValue,O=(0,t.useState)(l),I=O[0],D=O[1],L=l||I||"",A=uf((0,t.useRef)(null),null),M=A[0],R=A[1];Wd((0,t.useMemo)((function(){return{element:M,value:v,label:L,disabled:!!a}}),[a,M,L,v]),up,s);var F=(0,t.useCallback)((function(e){!l&&e&&D((function(t){return e.textContent&&t!==e.textContent?e.textContent:t||""}))}),[l]),P=!!_&&_===v,j=N===v,V=Ss(F,n,R,j?T:null,P?E:null);function U(){w({type:Sf.OptionMouseEnter,value:v,disabled:!!a})}function B(){w({type:Sf.OptionTouchStart,value:v,disabled:!!a})}function $(){w({type:Sf.ClearNavSelection})}function q(e){Jd(e.nativeEvent)||(e.preventDefault(),w({type:Sf.OptionMouseDown}))}function H(e){Jd(e.nativeEvent)||w({type:Sf.OptionMouseUp,value:v,callback:S,disabled:!!a})}function G(e){Jd(e.nativeEvent)||w({type:Sf.OptionClick,value:v,callback:S,disabled:!!a})}function z(){x!==Cf.Open&&_===v||w({type:Sf.OptionMouseMove,value:v,disabled:!!a})}return g(U,"handleMouseEnter"),g(B,"handleTouchStart"),g($,"handleMouseLeave"),g(q,"handleMouseDown"),g(H,"handleMouseUp"),g(G,"handleClick"),g(z,"handleMouseMove"),(0,t.createElement)(i,Df({"aria-selected":(C?P:j)||void 0,"aria-disabled":a||void 0,role:"option"},y,{ref:V,id:Cp(v),"data-reach-listbox-option":"","data-current-nav":P?"":void 0,"data-current-selected":j?"":void 0,"data-label":L,"data-value":v,onClick:xs(u,G),onMouseDown:xs(c,q),onMouseEnter:xs(d,U),onMouseLeave:xs(f,$),onMouseMove:xs(p,z),onMouseUp:xs(h,H),onTouchStart:xs(m,B)}),o)}),"ListboxOption"));function Tp(e){return[Cf.Navigating,Cf.Open,Cf.Dragging,Cf.Interacting].includes(e)}function wp(){var e=(0,t.useContext)(cp),n=e.send,r=e.disabled,i=e.onValueChange,o=e.stateData,a=o.navigationValue,s=o.typeaheadQuery,l=Qd(up),u=ef(i);(0,t.useEffect)((function(){s&&n({type:Sf.UpdateAfterTypeahead,query:s,callback:u});var e=window.setTimeout((function(){null!=s&&n({type:Sf.ClearTypeahead})}),1e3);return function(){window.clearTimeout(e)}}),[u,n,s]);var c=l.findIndex((function(e){return e.value===a}));return xs((function(e){var t=e.key,o=ys(t)&&1===t.length,s=l.find((function(e){return e.value===a}));switch(t){case"Enter":return void n({type:Sf.KeyDownEnter,value:a,callback:i,disabled:!!(null!=s&&s.disabled||r)});case" ":return e.preventDefault(),void n({type:Sf.KeyDownSpace,value:a,callback:i,disabled:!!(null!=s&&s.disabled||r)});case"Escape":return void n({type:Sf.KeyDownEscape});case"Tab":var u=e.shiftKey?Sf.KeyDownShiftTab:Sf.KeyDownTab;return void n({type:u});default:return void(o&&n({type:Sf.KeyDownSearch,query:t,disabled:r}))}}),Yd(up,{currentIndex:c,orientation:"vertical",key:"index",rotate:!0,filter:g((function(e){return!e.disabled}),"filter"),callback:g((function(e){n({type:Sf.KeyDownNavigate,value:l[e].value,disabled:r})}),"callback")}))}function Cp(e){var n=(0,t.useContext)(cp).listboxId;return e?lf("option-"+e,n):void 0}function Sp(e,t){return!(!e||!e.contains(t))}function xp(e,n,r){(0,t.useRef)(null!=e).current&&e!==n&&r()}function kp(e){var n=(0,t.useRef)(null);return(0,t.useEffect)((function(){n.current=e}),[e]),n.current}function Np(e,t){if(null==e)return{};var n,r,i={},o=Object.keys(e);for(r=0;r=0||(i[n]=e[n]);return i}function _p(){return _p=Object.assign||function(e){for(var t=1;t8||n>8)&&(C.current=!0)}V||null==j||p||E({type:Up,payload:{index:j,dropdownRef:T}})}function K(){C.current=!0,V||null==j||p||E({type:Up,payload:{index:j}})}function Q(e){Jd(e.nativeEvent)||(C.current?i?M.current?M.current=!1:O.current&&O.current.click():p||B():C.current=!0)}return S.current[j]=f,g(B,"select"),g($,"handleClick"),g(q,"handleDragStart"),g(H,"handleMouseDown"),g(G,"handleMouseEnter"),g(z,"handleMouseLeave"),g(W,"handleMouseMove"),g(K,"handleFocus"),g(Q,"handleMouseUp"),(0,t.useEffect)((function(){if(_){var e=window.setTimeout((function(){C.current=!0}),400);return function(){window.clearTimeout(e)}}C.current=!1}),[_,C]),(0,t.useEffect)((function(){var e=ms(O.current);return e.addEventListener("mouseup",t),function(){e.removeEventListener("mouseup",t)};function t(){M.current=!1}}),[]),{data:{disabled:p},props:_p({id:Zp(j),tabIndex:-1},y,{ref:U,"data-disabled":p?"":void 0,"data-selected":V?"":void 0,"data-valuetext":D,onClick:xs(o,$),onDragStart:xs(a,q),onMouseDown:xs(s,H),onMouseEnter:xs(l,G),onMouseLeave:xs(u,z),onMouseMove:xs(c,W),onFocus:xs(h,K),onMouseUp:xs(d,Q)})}}function Xp(e){e.id;var n=e.onKeyDown,r=e.ref,i=Np(e,Dp),o=Gp("useDropdownItems"),a=o.dispatch,s=o.triggerRef,l=o.dropdownRef,u=o.selectCallbacks,c=o.dropdownId,d=o.state,f=d.isExpanded,p=d.triggerId,h=d.selectionIndex,m=d.typeaheadQuery,v=rh(),y=Ss(l,r);(0,t.useEffect)((function(){var e=Jp(v,m);m&&null!=e&&a({type:Up,payload:{index:e,dropdownRef:l}});var t=window.setTimeout((function(){return m&&a({type:Vp,payload:""})}),1e3);return function(){return window.clearTimeout(t)}}),[a,v,m,l]);var b=kp(v.length),E=kp(v[h]),T=kp(h);(0,t.useEffect)((function(){h>v.length-1?a({type:Up,payload:{index:v.length-1,dropdownRef:l}}):b!==v.length&&h>-1&&E&&T===h&&v[h]!==E&&a({type:Up,payload:{index:v.findIndex((function(e){return e.key===(null==E?void 0:E.key)})),dropdownRef:l}})}),[l,a,v,b,E,T,h]);var w=xs(g((function(e){var t=e.key;if(f)switch(t){case"Enter":case" ":var n=v.find((function(e){return e.index===h}));n&&!n.disabled&&(e.preventDefault(),n.isLink&&n.element?n.element.click():(eh(s.current),u.current[n.index]&&u.current[n.index](),a({type:Mp})));break;case"Escape":eh(s.current),a({type:Rp});break;case"Tab":e.preventDefault();break;default:if(ys(t)&&1===t.length){var r=m+t.toLowerCase();a({type:Vp,payload:r})}}}),"handleKeyDown"),Yd($p,{currentIndex:h,orientation:"vertical",rotate:!1,filter:g((function(e){return!e.disabled}),"filter"),callback:g((function(e){a({type:Up,payload:{index:e,dropdownRef:l}})}),"callback"),key:"index"}));return{data:{activeDescendant:Zp(h)||void 0,triggerId:p},props:_p({tabIndex:-1},i,{ref:y,id:c,onKeyDown:xs(n,w)})}}function Yp(e){var n=e.onBlur,r=e.portal,i=void 0===r||r,o=e.position,a=e.ref,s=Np(e,Lp),l=Gp("useDropdownPopover"),u=l.triggerRef,c=l.triggerClickedRef,d=l.dispatch,f=l.dropdownRef,p=l.popoverRef,h=l.state.isExpanded,m=Ss(p,a);return(0,t.useEffect)((function(){if(h){var e=ms(p.current);return g(t,"listener"),e.addEventListener("mousedown",t),function(){e.removeEventListener("mousedown",t)}}function t(e){c.current?c.current=!1:th(p.current,e.target)||d({type:Rp})}}),[c,u,d,f,p,h]),{data:{portal:i,position:o,targetRef:u,isExpanded:h},props:_p({ref:m,hidden:!h,onBlur:xs(n,(function(e){e.currentTarget.contains(e.relatedTarget)||d({type:Rp})}))},s)}}function Jp(e,t){if(void 0===t&&(t=""),!t)return null;var n=e.find((function(e){var n,r,i;return!e.disabled&&(null==(n=e.element)||null==(r=n.dataset)||null==(i=r.valuetext)?void 0:i.toLowerCase().startsWith(t))}));return n?e.indexOf(n):null}function Zp(e){var t=Gp("useItemId").dropdownId;return null!=e&&e>-1?lf("option-"+e,t):void 0}function eh(e){e&&e.focus()}function th(e,t){return!(!e||!e.contains(t))}function nh(e,t){switch(void 0===t&&(t={}),t.type){case Mp:case Rp:return _p({},e,{isExpanded:!1,selectionIndex:-1});case Fp:return _p({},e,{isExpanded:!0,selectionIndex:0});case Pp:return _p({},e,{isExpanded:!0,selectionIndex:t.payload.index});case jp:return _p({},e,{isExpanded:!0,selectionIndex:-1});case Up:var n=t.payload.dropdownRef,r=void 0===n?{current:null}:n;if(t.payload.index>=0&&t.payload.index!==e.selectionIndex){if(r.current){var i=ms(r.current);r.current!==(null==i?void 0:i.activeElement)&&r.current.focus()}return _p({},e,{selectionIndex:null!=t.payload.max?Math.min(Math.max(t.payload.index,0),t.payload.max):Math.max(t.payload.index,0)})}return e;case Ap:return _p({},e,{selectionIndex:-1});case Bp:return _p({},e,{triggerId:t.payload});case Vp:return void 0!==t.payload?_p({},e,{typeaheadQuery:t.payload}):e;default:return e}}function rh(){return Qd($p)}g(Kp,"useDropdownTrigger"),g(Qp,"useDropdownItem"),g(Xp,"useDropdownItems"),g(Yp,"useDropdownPopover"),g(Jp,"findItemFromTypeahead"),g(Zp,"useItemId"),g(eh,"focus"),g(th,"popoverContainsEventTarget"),g(nh,"reducer$1"),g(rh,"useDropdownDescendants");var ih={exports:{}},oh={},ah="function"==typeof Symbol&&Symbol.for,sh=ah?Symbol.for("react.element"):60103,lh=ah?Symbol.for("react.portal"):60106,uh=ah?Symbol.for("react.fragment"):60107,ch=ah?Symbol.for("react.strict_mode"):60108,dh=ah?Symbol.for("react.profiler"):60114,fh=ah?Symbol.for("react.provider"):60109,ph=ah?Symbol.for("react.context"):60110,hh=ah?Symbol.for("react.async_mode"):60111,mh=ah?Symbol.for("react.concurrent_mode"):60111,gh=ah?Symbol.for("react.forward_ref"):60112,vh=ah?Symbol.for("react.suspense"):60113,yh=ah?Symbol.for("react.suspense_list"):60120,bh=ah?Symbol.for("react.memo"):60115,Eh=ah?Symbol.for("react.lazy"):60116,Th=ah?Symbol.for("react.block"):60121,wh=ah?Symbol.for("react.fundamental"):60117,Ch=ah?Symbol.for("react.responder"):60118,Sh=ah?Symbol.for("react.scope"):60119;function xh(e){if("object"==typeof e&&null!==e){var t=e.$$typeof;switch(t){case sh:switch(e=e.type){case hh:case mh:case uh:case dh:case ch:case vh:return e;default:switch(e=e&&e.$$typeof){case ph:case gh:case Eh:case bh:case fh:return e;default:return t}}case lh:return t}}}function kh(e){return xh(e)===mh}function Nh(){return Nh=Object.assign||function(e){for(var t=1;t=0||(i[n]=e[n]);return i}g(xh,"z"),g(kh,"A"),oh.AsyncMode=hh,oh.ConcurrentMode=mh,oh.ContextConsumer=ph,oh.ContextProvider=fh,oh.Element=sh,oh.ForwardRef=gh,oh.Fragment=uh,oh.Lazy=Eh,oh.Memo=bh,oh.Portal=lh,oh.Profiler=dh,oh.StrictMode=ch,oh.Suspense=vh,oh.isAsyncMode=function(e){return kh(e)||xh(e)===hh},oh.isConcurrentMode=kh,oh.isContextConsumer=function(e){return xh(e)===ph},oh.isContextProvider=function(e){return xh(e)===fh},oh.isElement=function(e){return"object"==typeof e&&null!==e&&e.$$typeof===sh},oh.isForwardRef=function(e){return xh(e)===gh},oh.isFragment=function(e){return xh(e)===uh},oh.isLazy=function(e){return xh(e)===Eh},oh.isMemo=function(e){return xh(e)===bh},oh.isPortal=function(e){return xh(e)===lh},oh.isProfiler=function(e){return xh(e)===dh},oh.isStrictMode=function(e){return xh(e)===ch},oh.isSuspense=function(e){return xh(e)===vh},oh.isValidElementType=function(e){return"string"==typeof e||"function"==typeof e||e===uh||e===mh||e===dh||e===ch||e===vh||e===yh||"object"==typeof e&&null!==e&&(e.$$typeof===Eh||e.$$typeof===bh||e.$$typeof===fh||e.$$typeof===ph||e.$$typeof===gh||e.$$typeof===wh||e.$$typeof===Ch||e.$$typeof===Sh||e.$$typeof===Th)},oh.typeOf=xh,ih.exports=oh,g(Nh,"_extends$2"),g(_h,"_objectWithoutPropertiesLoose$2");var Oh=["as","id","children"],Ih=["as"],Dh=["as"],Lh=["as"],Ah=["as"],Mh=["portal"],Rh=["as"],Fh=(0,t.forwardRef)((function(e,n){var r=e.as,i=void 0===r?t.Fragment:r,o=e.id,a=e.children,s=_h(e,Oh),l=(0,t.useMemo)((function(){try{return ih.exports.isFragment((0,t.createElement)(i,null))}catch(e){return!1}}),[i])?{}:Nh({ref:n,id:o,"data-reach-menu":""},s);return(0,t.createElement)(i,l,(0,t.createElement)(Wp,{id:o,children:a}))})),Ph=(0,t.forwardRef)((function(e,n){var r=e.as,i=void 0===r?"button":r,o=Kp(Nh({},_h(e,Ih),{ref:n})),a=o.data,s=a.isExpanded,l=a.controls,u=o.props;return(0,t.createElement)(i,Nh({"aria-expanded":!!s||void 0,"aria-haspopup":!0,"aria-controls":l},u,{"data-reach-menu-button":""}))})),jh=(0,t.forwardRef)((function(e,n){var r=e.as,i=void 0===r?"div":r,o=Qp(Nh({},_h(e,Dh),{ref:n})),a=o.data.disabled,s=o.props;return(0,t.createElement)(i,Nh({role:"menuitem"},s,{"aria-disabled":a||void 0,"data-reach-menu-item":""}))})),Vh=(0,t.forwardRef)((function(e,n){var r=e.as,i=void 0===r?"div":r,o=_h(e,Lh);return(0,t.createElement)(jh,Nh({},o,{ref:n,as:i}))})),Uh=(0,t.forwardRef)((function(e,n){var r=e.as,i=void 0===r?"div":r,o=Xp(Nh({},_h(e,Ah),{ref:n})),a=o.data,s=a.activeDescendant,l=a.triggerId,u=o.props;return(0,t.createElement)(i,Nh({"aria-activedescendant":s,"aria-labelledby":l||void 0,role:"menu"},u,{"data-reach-menu-items":""}))})),Bh=(0,t.forwardRef)((function(e,n){var r=e.portal,i=void 0===r||r,o=_h(e,Mh);return(0,t.createElement)($h,{portal:i},(0,t.createElement)(Uh,Nh({},o,{ref:n,"data-reach-menu-list":""})))})),$h=(0,t.forwardRef)((function(e,n){var r=e.as,i=void 0===r?"div":r,o=Yp(Nh({},_h(e,Rh),{ref:n})),a=o.data,s=a.portal,l=a.targetRef,u=a.position,c=o.props,d={"data-reach-menu-popover":""};return s?(0,t.createElement)(Rd,Nh({},c,d,{as:i,targetRef:l,position:u,unstable_skipInitialPortalRender:!0})):(0,t.createElement)(i,Nh({},c,d))}));const qh=(0,t.forwardRef)(((e,t)=>de(Ph,m(h({},e),{ref:t,className:b("graphiql-un-styled",e.className)}))));qh.displayName="MenuButton";const Hh=Xc(Fh,{Button:qh,Item:Vh,List:Bh});e.aK=Hh;const Gh=(0,t.forwardRef)(((e,t)=>de(hp,m(h({},e),{ref:t,className:b("graphiql-un-styled",e.className)}))));Gh.displayName="ListboxButton";const zh=Xc(fp,{Button:Gh,Input:dp,Option:Ep,Popover:yp});e.aL=zh;var Wh={};var Kh={Aacute:"Á",aacute:"á",Abreve:"Ă",abreve:"ă",ac:"∾",acd:"∿",acE:"∾̳",Acirc:"Â",acirc:"â",acute:"´",Acy:"А",acy:"а",AElig:"Æ",aelig:"æ",af:"⁡",Afr:"𝔄",afr:"𝔞",Agrave:"À",agrave:"à",alefsym:"ℵ",aleph:"ℵ",Alpha:"Α",alpha:"α",Amacr:"Ā",amacr:"ā",amalg:"⨿",amp:"&",AMP:"&",andand:"⩕",And:"⩓",and:"∧",andd:"⩜",andslope:"⩘",andv:"⩚",ang:"∠",ange:"⦤",angle:"∠",angmsdaa:"⦨",angmsdab:"⦩",angmsdac:"⦪",angmsdad:"⦫",angmsdae:"⦬",angmsdaf:"⦭",angmsdag:"⦮",angmsdah:"⦯",angmsd:"∡",angrt:"∟",angrtvb:"⊾",angrtvbd:"⦝",angsph:"∢",angst:"Å",angzarr:"⍼",Aogon:"Ą",aogon:"ą",Aopf:"𝔸",aopf:"𝕒",apacir:"⩯",ap:"≈",apE:"⩰",ape:"≊",apid:"≋",apos:"'",ApplyFunction:"⁡",approx:"≈",approxeq:"≊",Aring:"Å",aring:"å",Ascr:"𝒜",ascr:"𝒶",Assign:"≔",ast:"*",asymp:"≈",asympeq:"≍",Atilde:"Ã",atilde:"ã",Auml:"Ä",auml:"ä",awconint:"∳",awint:"⨑",backcong:"≌",backepsilon:"϶",backprime:"‵",backsim:"∽",backsimeq:"⋍",Backslash:"∖",Barv:"⫧",barvee:"⊽",barwed:"⌅",Barwed:"⌆",barwedge:"⌅",bbrk:"⎵",bbrktbrk:"⎶",bcong:"≌",Bcy:"Б",bcy:"б",bdquo:"„",becaus:"∵",because:"∵",Because:"∵",bemptyv:"⦰",bepsi:"϶",bernou:"ℬ",Bernoullis:"ℬ",Beta:"Β",beta:"β",beth:"ℶ",between:"≬",Bfr:"𝔅",bfr:"𝔟",bigcap:"⋂",bigcirc:"◯",bigcup:"⋃",bigodot:"⨀",bigoplus:"⨁",bigotimes:"⨂",bigsqcup:"⨆",bigstar:"★",bigtriangledown:"▽",bigtriangleup:"△",biguplus:"⨄",bigvee:"⋁",bigwedge:"⋀",bkarow:"⤍",blacklozenge:"⧫",blacksquare:"▪",blacktriangle:"▴",blacktriangledown:"▾",blacktriangleleft:"◂",blacktriangleright:"▸",blank:"␣",blk12:"▒",blk14:"░",blk34:"▓",block:"█",bne:"=⃥",bnequiv:"≡⃥",bNot:"⫭",bnot:"⌐",Bopf:"𝔹",bopf:"𝕓",bot:"⊥",bottom:"⊥",bowtie:"⋈",boxbox:"⧉",boxdl:"┐",boxdL:"╕",boxDl:"╖",boxDL:"╗",boxdr:"┌",boxdR:"╒",boxDr:"╓",boxDR:"╔",boxh:"─",boxH:"═",boxhd:"┬",boxHd:"╤",boxhD:"╥",boxHD:"╦",boxhu:"┴",boxHu:"╧",boxhU:"╨",boxHU:"╩",boxminus:"⊟",boxplus:"⊞",boxtimes:"⊠",boxul:"┘",boxuL:"╛",boxUl:"╜",boxUL:"╝",boxur:"└",boxuR:"╘",boxUr:"╙",boxUR:"╚",boxv:"│",boxV:"║",boxvh:"┼",boxvH:"╪",boxVh:"╫",boxVH:"╬",boxvl:"┤",boxvL:"╡",boxVl:"╢",boxVL:"╣",boxvr:"├",boxvR:"╞",boxVr:"╟",boxVR:"╠",bprime:"‵",breve:"˘",Breve:"˘",brvbar:"¦",bscr:"𝒷",Bscr:"ℬ",bsemi:"⁏",bsim:"∽",bsime:"⋍",bsolb:"⧅",bsol:"\\",bsolhsub:"⟈",bull:"•",bullet:"•",bump:"≎",bumpE:"⪮",bumpe:"≏",Bumpeq:"≎",bumpeq:"≏",Cacute:"Ć",cacute:"ć",capand:"⩄",capbrcup:"⩉",capcap:"⩋",cap:"∩",Cap:"⋒",capcup:"⩇",capdot:"⩀",CapitalDifferentialD:"ⅅ",caps:"∩︀",caret:"⁁",caron:"ˇ",Cayleys:"ℭ",ccaps:"⩍",Ccaron:"Č",ccaron:"č",Ccedil:"Ç",ccedil:"ç",Ccirc:"Ĉ",ccirc:"ĉ",Cconint:"∰",ccups:"⩌",ccupssm:"⩐",Cdot:"Ċ",cdot:"ċ",cedil:"¸",Cedilla:"¸",cemptyv:"⦲",cent:"¢",centerdot:"·",CenterDot:"·",cfr:"𝔠",Cfr:"ℭ",CHcy:"Ч",chcy:"ч",check:"✓",checkmark:"✓",Chi:"Χ",chi:"χ",circ:"ˆ",circeq:"≗",circlearrowleft:"↺",circlearrowright:"↻",circledast:"⊛",circledcirc:"⊚",circleddash:"⊝",CircleDot:"⊙",circledR:"®",circledS:"Ⓢ",CircleMinus:"⊖",CirclePlus:"⊕",CircleTimes:"⊗",cir:"○",cirE:"⧃",cire:"≗",cirfnint:"⨐",cirmid:"⫯",cirscir:"⧂",ClockwiseContourIntegral:"∲",CloseCurlyDoubleQuote:"”",CloseCurlyQuote:"’",clubs:"♣",clubsuit:"♣",colon:":",Colon:"∷",Colone:"⩴",colone:"≔",coloneq:"≔",comma:",",commat:"@",comp:"∁",compfn:"∘",complement:"∁",complexes:"ℂ",cong:"≅",congdot:"⩭",Congruent:"≡",conint:"∮",Conint:"∯",ContourIntegral:"∮",copf:"𝕔",Copf:"ℂ",coprod:"∐",Coproduct:"∐",copy:"©",COPY:"©",copysr:"℗",CounterClockwiseContourIntegral:"∳",crarr:"↵",cross:"✗",Cross:"⨯",Cscr:"𝒞",cscr:"𝒸",csub:"⫏",csube:"⫑",csup:"⫐",csupe:"⫒",ctdot:"⋯",cudarrl:"⤸",cudarrr:"⤵",cuepr:"⋞",cuesc:"⋟",cularr:"↶",cularrp:"⤽",cupbrcap:"⩈",cupcap:"⩆",CupCap:"≍",cup:"∪",Cup:"⋓",cupcup:"⩊",cupdot:"⊍",cupor:"⩅",cups:"∪︀",curarr:"↷",curarrm:"⤼",curlyeqprec:"⋞",curlyeqsucc:"⋟",curlyvee:"⋎",curlywedge:"⋏",curren:"¤",curvearrowleft:"↶",curvearrowright:"↷",cuvee:"⋎",cuwed:"⋏",cwconint:"∲",cwint:"∱",cylcty:"⌭",dagger:"†",Dagger:"‡",daleth:"ℸ",darr:"↓",Darr:"↡",dArr:"⇓",dash:"‐",Dashv:"⫤",dashv:"⊣",dbkarow:"⤏",dblac:"˝",Dcaron:"Ď",dcaron:"ď",Dcy:"Д",dcy:"д",ddagger:"‡",ddarr:"⇊",DD:"ⅅ",dd:"ⅆ",DDotrahd:"⤑",ddotseq:"⩷",deg:"°",Del:"∇",Delta:"Δ",delta:"δ",demptyv:"⦱",dfisht:"⥿",Dfr:"𝔇",dfr:"𝔡",dHar:"⥥",dharl:"⇃",dharr:"⇂",DiacriticalAcute:"´",DiacriticalDot:"˙",DiacriticalDoubleAcute:"˝",DiacriticalGrave:"`",DiacriticalTilde:"˜",diam:"⋄",diamond:"⋄",Diamond:"⋄",diamondsuit:"♦",diams:"♦",die:"¨",DifferentialD:"ⅆ",digamma:"ϝ",disin:"⋲",div:"÷",divide:"÷",divideontimes:"⋇",divonx:"⋇",DJcy:"Ђ",djcy:"ђ",dlcorn:"⌞",dlcrop:"⌍",dollar:"$",Dopf:"𝔻",dopf:"𝕕",Dot:"¨",dot:"˙",DotDot:"⃜",doteq:"≐",doteqdot:"≑",DotEqual:"≐",dotminus:"∸",dotplus:"∔",dotsquare:"⊡",doublebarwedge:"⌆",DoubleContourIntegral:"∯",DoubleDot:"¨",DoubleDownArrow:"⇓",DoubleLeftArrow:"⇐",DoubleLeftRightArrow:"⇔",DoubleLeftTee:"⫤",DoubleLongLeftArrow:"⟸",DoubleLongLeftRightArrow:"⟺",DoubleLongRightArrow:"⟹",DoubleRightArrow:"⇒",DoubleRightTee:"⊨",DoubleUpArrow:"⇑",DoubleUpDownArrow:"⇕",DoubleVerticalBar:"∥",DownArrowBar:"⤓",downarrow:"↓",DownArrow:"↓",Downarrow:"⇓",DownArrowUpArrow:"⇵",DownBreve:"̑",downdownarrows:"⇊",downharpoonleft:"⇃",downharpoonright:"⇂",DownLeftRightVector:"⥐",DownLeftTeeVector:"⥞",DownLeftVectorBar:"⥖",DownLeftVector:"↽",DownRightTeeVector:"⥟",DownRightVectorBar:"⥗",DownRightVector:"⇁",DownTeeArrow:"↧",DownTee:"⊤",drbkarow:"⤐",drcorn:"⌟",drcrop:"⌌",Dscr:"𝒟",dscr:"𝒹",DScy:"Ѕ",dscy:"ѕ",dsol:"⧶",Dstrok:"Đ",dstrok:"đ",dtdot:"⋱",dtri:"▿",dtrif:"▾",duarr:"⇵",duhar:"⥯",dwangle:"⦦",DZcy:"Џ",dzcy:"џ",dzigrarr:"⟿",Eacute:"É",eacute:"é",easter:"⩮",Ecaron:"Ě",ecaron:"ě",Ecirc:"Ê",ecirc:"ê",ecir:"≖",ecolon:"≕",Ecy:"Э",ecy:"э",eDDot:"⩷",Edot:"Ė",edot:"ė",eDot:"≑",ee:"ⅇ",efDot:"≒",Efr:"𝔈",efr:"𝔢",eg:"⪚",Egrave:"È",egrave:"è",egs:"⪖",egsdot:"⪘",el:"⪙",Element:"∈",elinters:"⏧",ell:"ℓ",els:"⪕",elsdot:"⪗",Emacr:"Ē",emacr:"ē",empty:"∅",emptyset:"∅",EmptySmallSquare:"◻",emptyv:"∅",EmptyVerySmallSquare:"▫",emsp13:" ",emsp14:" ",emsp:" ",ENG:"Ŋ",eng:"ŋ",ensp:" ",Eogon:"Ę",eogon:"ę",Eopf:"𝔼",eopf:"𝕖",epar:"⋕",eparsl:"⧣",eplus:"⩱",epsi:"ε",Epsilon:"Ε",epsilon:"ε",epsiv:"ϵ",eqcirc:"≖",eqcolon:"≕",eqsim:"≂",eqslantgtr:"⪖",eqslantless:"⪕",Equal:"⩵",equals:"=",EqualTilde:"≂",equest:"≟",Equilibrium:"⇌",equiv:"≡",equivDD:"⩸",eqvparsl:"⧥",erarr:"⥱",erDot:"≓",escr:"ℯ",Escr:"ℰ",esdot:"≐",Esim:"⩳",esim:"≂",Eta:"Η",eta:"η",ETH:"Ð",eth:"ð",Euml:"Ë",euml:"ë",euro:"€",excl:"!",exist:"∃",Exists:"∃",expectation:"ℰ",exponentiale:"ⅇ",ExponentialE:"ⅇ",fallingdotseq:"≒",Fcy:"Ф",fcy:"ф",female:"♀",ffilig:"ffi",fflig:"ff",ffllig:"ffl",Ffr:"𝔉",ffr:"𝔣",filig:"fi",FilledSmallSquare:"◼",FilledVerySmallSquare:"▪",fjlig:"fj",flat:"♭",fllig:"fl",fltns:"▱",fnof:"ƒ",Fopf:"𝔽",fopf:"𝕗",forall:"∀",ForAll:"∀",fork:"⋔",forkv:"⫙",Fouriertrf:"ℱ",fpartint:"⨍",frac12:"½",frac13:"⅓",frac14:"¼",frac15:"⅕",frac16:"⅙",frac18:"⅛",frac23:"⅔",frac25:"⅖",frac34:"¾",frac35:"⅗",frac38:"⅜",frac45:"⅘",frac56:"⅚",frac58:"⅝",frac78:"⅞",frasl:"⁄",frown:"⌢",fscr:"𝒻",Fscr:"ℱ",gacute:"ǵ",Gamma:"Γ",gamma:"γ",Gammad:"Ϝ",gammad:"ϝ",gap:"⪆",Gbreve:"Ğ",gbreve:"ğ",Gcedil:"Ģ",Gcirc:"Ĝ",gcirc:"ĝ",Gcy:"Г",gcy:"г",Gdot:"Ġ",gdot:"ġ",ge:"≥",gE:"≧",gEl:"⪌",gel:"⋛",geq:"≥",geqq:"≧",geqslant:"⩾",gescc:"⪩",ges:"⩾",gesdot:"⪀",gesdoto:"⪂",gesdotol:"⪄",gesl:"⋛︀",gesles:"⪔",Gfr:"𝔊",gfr:"𝔤",gg:"≫",Gg:"⋙",ggg:"⋙",gimel:"ℷ",GJcy:"Ѓ",gjcy:"ѓ",gla:"⪥",gl:"≷",glE:"⪒",glj:"⪤",gnap:"⪊",gnapprox:"⪊",gne:"⪈",gnE:"≩",gneq:"⪈",gneqq:"≩",gnsim:"⋧",Gopf:"𝔾",gopf:"𝕘",grave:"`",GreaterEqual:"≥",GreaterEqualLess:"⋛",GreaterFullEqual:"≧",GreaterGreater:"⪢",GreaterLess:"≷",GreaterSlantEqual:"⩾",GreaterTilde:"≳",Gscr:"𝒢",gscr:"ℊ",gsim:"≳",gsime:"⪎",gsiml:"⪐",gtcc:"⪧",gtcir:"⩺",gt:">",GT:">",Gt:"≫",gtdot:"⋗",gtlPar:"⦕",gtquest:"⩼",gtrapprox:"⪆",gtrarr:"⥸",gtrdot:"⋗",gtreqless:"⋛",gtreqqless:"⪌",gtrless:"≷",gtrsim:"≳",gvertneqq:"≩︀",gvnE:"≩︀",Hacek:"ˇ",hairsp:" ",half:"½",hamilt:"ℋ",HARDcy:"Ъ",hardcy:"ъ",harrcir:"⥈",harr:"↔",hArr:"⇔",harrw:"↭",Hat:"^",hbar:"ℏ",Hcirc:"Ĥ",hcirc:"ĥ",hearts:"♥",heartsuit:"♥",hellip:"…",hercon:"⊹",hfr:"𝔥",Hfr:"ℌ",HilbertSpace:"ℋ",hksearow:"⤥",hkswarow:"⤦",hoarr:"⇿",homtht:"∻",hookleftarrow:"↩",hookrightarrow:"↪",hopf:"𝕙",Hopf:"ℍ",horbar:"―",HorizontalLine:"─",hscr:"𝒽",Hscr:"ℋ",hslash:"ℏ",Hstrok:"Ħ",hstrok:"ħ",HumpDownHump:"≎",HumpEqual:"≏",hybull:"⁃",hyphen:"‐",Iacute:"Í",iacute:"í",ic:"⁣",Icirc:"Î",icirc:"î",Icy:"И",icy:"и",Idot:"İ",IEcy:"Е",iecy:"е",iexcl:"¡",iff:"⇔",ifr:"𝔦",Ifr:"ℑ",Igrave:"Ì",igrave:"ì",ii:"ⅈ",iiiint:"⨌",iiint:"∭",iinfin:"⧜",iiota:"℩",IJlig:"IJ",ijlig:"ij",Imacr:"Ī",imacr:"ī",image:"ℑ",ImaginaryI:"ⅈ",imagline:"ℐ",imagpart:"ℑ",imath:"ı",Im:"ℑ",imof:"⊷",imped:"Ƶ",Implies:"⇒",incare:"℅",in:"∈",infin:"∞",infintie:"⧝",inodot:"ı",intcal:"⊺",int:"∫",Int:"∬",integers:"ℤ",Integral:"∫",intercal:"⊺",Intersection:"⋂",intlarhk:"⨗",intprod:"⨼",InvisibleComma:"⁣",InvisibleTimes:"⁢",IOcy:"Ё",iocy:"ё",Iogon:"Į",iogon:"į",Iopf:"𝕀",iopf:"𝕚",Iota:"Ι",iota:"ι",iprod:"⨼",iquest:"¿",iscr:"𝒾",Iscr:"ℐ",isin:"∈",isindot:"⋵",isinE:"⋹",isins:"⋴",isinsv:"⋳",isinv:"∈",it:"⁢",Itilde:"Ĩ",itilde:"ĩ",Iukcy:"І",iukcy:"і",Iuml:"Ï",iuml:"ï",Jcirc:"Ĵ",jcirc:"ĵ",Jcy:"Й",jcy:"й",Jfr:"𝔍",jfr:"𝔧",jmath:"ȷ",Jopf:"𝕁",jopf:"𝕛",Jscr:"𝒥",jscr:"𝒿",Jsercy:"Ј",jsercy:"ј",Jukcy:"Є",jukcy:"є",Kappa:"Κ",kappa:"κ",kappav:"ϰ",Kcedil:"Ķ",kcedil:"ķ",Kcy:"К",kcy:"к",Kfr:"𝔎",kfr:"𝔨",kgreen:"ĸ",KHcy:"Х",khcy:"х",KJcy:"Ќ",kjcy:"ќ",Kopf:"𝕂",kopf:"𝕜",Kscr:"𝒦",kscr:"𝓀",lAarr:"⇚",Lacute:"Ĺ",lacute:"ĺ",laemptyv:"⦴",lagran:"ℒ",Lambda:"Λ",lambda:"λ",lang:"⟨",Lang:"⟪",langd:"⦑",langle:"⟨",lap:"⪅",Laplacetrf:"ℒ",laquo:"«",larrb:"⇤",larrbfs:"⤟",larr:"←",Larr:"↞",lArr:"⇐",larrfs:"⤝",larrhk:"↩",larrlp:"↫",larrpl:"⤹",larrsim:"⥳",larrtl:"↢",latail:"⤙",lAtail:"⤛",lat:"⪫",late:"⪭",lates:"⪭︀",lbarr:"⤌",lBarr:"⤎",lbbrk:"❲",lbrace:"{",lbrack:"[",lbrke:"⦋",lbrksld:"⦏",lbrkslu:"⦍",Lcaron:"Ľ",lcaron:"ľ",Lcedil:"Ļ",lcedil:"ļ",lceil:"⌈",lcub:"{",Lcy:"Л",lcy:"л",ldca:"⤶",ldquo:"“",ldquor:"„",ldrdhar:"⥧",ldrushar:"⥋",ldsh:"↲",le:"≤",lE:"≦",LeftAngleBracket:"⟨",LeftArrowBar:"⇤",leftarrow:"←",LeftArrow:"←",Leftarrow:"⇐",LeftArrowRightArrow:"⇆",leftarrowtail:"↢",LeftCeiling:"⌈",LeftDoubleBracket:"⟦",LeftDownTeeVector:"⥡",LeftDownVectorBar:"⥙",LeftDownVector:"⇃",LeftFloor:"⌊",leftharpoondown:"↽",leftharpoonup:"↼",leftleftarrows:"⇇",leftrightarrow:"↔",LeftRightArrow:"↔",Leftrightarrow:"⇔",leftrightarrows:"⇆",leftrightharpoons:"⇋",leftrightsquigarrow:"↭",LeftRightVector:"⥎",LeftTeeArrow:"↤",LeftTee:"⊣",LeftTeeVector:"⥚",leftthreetimes:"⋋",LeftTriangleBar:"⧏",LeftTriangle:"⊲",LeftTriangleEqual:"⊴",LeftUpDownVector:"⥑",LeftUpTeeVector:"⥠",LeftUpVectorBar:"⥘",LeftUpVector:"↿",LeftVectorBar:"⥒",LeftVector:"↼",lEg:"⪋",leg:"⋚",leq:"≤",leqq:"≦",leqslant:"⩽",lescc:"⪨",les:"⩽",lesdot:"⩿",lesdoto:"⪁",lesdotor:"⪃",lesg:"⋚︀",lesges:"⪓",lessapprox:"⪅",lessdot:"⋖",lesseqgtr:"⋚",lesseqqgtr:"⪋",LessEqualGreater:"⋚",LessFullEqual:"≦",LessGreater:"≶",lessgtr:"≶",LessLess:"⪡",lesssim:"≲",LessSlantEqual:"⩽",LessTilde:"≲",lfisht:"⥼",lfloor:"⌊",Lfr:"𝔏",lfr:"𝔩",lg:"≶",lgE:"⪑",lHar:"⥢",lhard:"↽",lharu:"↼",lharul:"⥪",lhblk:"▄",LJcy:"Љ",ljcy:"љ",llarr:"⇇",ll:"≪",Ll:"⋘",llcorner:"⌞",Lleftarrow:"⇚",llhard:"⥫",lltri:"◺",Lmidot:"Ŀ",lmidot:"ŀ",lmoustache:"⎰",lmoust:"⎰",lnap:"⪉",lnapprox:"⪉",lne:"⪇",lnE:"≨",lneq:"⪇",lneqq:"≨",lnsim:"⋦",loang:"⟬",loarr:"⇽",lobrk:"⟦",longleftarrow:"⟵",LongLeftArrow:"⟵",Longleftarrow:"⟸",longleftrightarrow:"⟷",LongLeftRightArrow:"⟷",Longleftrightarrow:"⟺",longmapsto:"⟼",longrightarrow:"⟶",LongRightArrow:"⟶",Longrightarrow:"⟹",looparrowleft:"↫",looparrowright:"↬",lopar:"⦅",Lopf:"𝕃",lopf:"𝕝",loplus:"⨭",lotimes:"⨴",lowast:"∗",lowbar:"_",LowerLeftArrow:"↙",LowerRightArrow:"↘",loz:"◊",lozenge:"◊",lozf:"⧫",lpar:"(",lparlt:"⦓",lrarr:"⇆",lrcorner:"⌟",lrhar:"⇋",lrhard:"⥭",lrm:"‎",lrtri:"⊿",lsaquo:"‹",lscr:"𝓁",Lscr:"ℒ",lsh:"↰",Lsh:"↰",lsim:"≲",lsime:"⪍",lsimg:"⪏",lsqb:"[",lsquo:"‘",lsquor:"‚",Lstrok:"Ł",lstrok:"ł",ltcc:"⪦",ltcir:"⩹",lt:"<",LT:"<",Lt:"≪",ltdot:"⋖",lthree:"⋋",ltimes:"⋉",ltlarr:"⥶",ltquest:"⩻",ltri:"◃",ltrie:"⊴",ltrif:"◂",ltrPar:"⦖",lurdshar:"⥊",luruhar:"⥦",lvertneqq:"≨︀",lvnE:"≨︀",macr:"¯",male:"♂",malt:"✠",maltese:"✠",Map:"⤅",map:"↦",mapsto:"↦",mapstodown:"↧",mapstoleft:"↤",mapstoup:"↥",marker:"▮",mcomma:"⨩",Mcy:"М",mcy:"м",mdash:"—",mDDot:"∺",measuredangle:"∡",MediumSpace:" ",Mellintrf:"ℳ",Mfr:"𝔐",mfr:"𝔪",mho:"℧",micro:"µ",midast:"*",midcir:"⫰",mid:"∣",middot:"·",minusb:"⊟",minus:"−",minusd:"∸",minusdu:"⨪",MinusPlus:"∓",mlcp:"⫛",mldr:"…",mnplus:"∓",models:"⊧",Mopf:"𝕄",mopf:"𝕞",mp:"∓",mscr:"𝓂",Mscr:"ℳ",mstpos:"∾",Mu:"Μ",mu:"μ",multimap:"⊸",mumap:"⊸",nabla:"∇",Nacute:"Ń",nacute:"ń",nang:"∠⃒",nap:"≉",napE:"⩰̸",napid:"≋̸",napos:"ʼn",napprox:"≉",natural:"♮",naturals:"ℕ",natur:"♮",nbsp:" ",nbump:"≎̸",nbumpe:"≏̸",ncap:"⩃",Ncaron:"Ň",ncaron:"ň",Ncedil:"Ņ",ncedil:"ņ",ncong:"≇",ncongdot:"⩭̸",ncup:"⩂",Ncy:"Н",ncy:"н",ndash:"–",nearhk:"⤤",nearr:"↗",neArr:"⇗",nearrow:"↗",ne:"≠",nedot:"≐̸",NegativeMediumSpace:"​",NegativeThickSpace:"​",NegativeThinSpace:"​",NegativeVeryThinSpace:"​",nequiv:"≢",nesear:"⤨",nesim:"≂̸",NestedGreaterGreater:"≫",NestedLessLess:"≪",NewLine:"\n",nexist:"∄",nexists:"∄",Nfr:"𝔑",nfr:"𝔫",ngE:"≧̸",nge:"≱",ngeq:"≱",ngeqq:"≧̸",ngeqslant:"⩾̸",nges:"⩾̸",nGg:"⋙̸",ngsim:"≵",nGt:"≫⃒",ngt:"≯",ngtr:"≯",nGtv:"≫̸",nharr:"↮",nhArr:"⇎",nhpar:"⫲",ni:"∋",nis:"⋼",nisd:"⋺",niv:"∋",NJcy:"Њ",njcy:"њ",nlarr:"↚",nlArr:"⇍",nldr:"‥",nlE:"≦̸",nle:"≰",nleftarrow:"↚",nLeftarrow:"⇍",nleftrightarrow:"↮",nLeftrightarrow:"⇎",nleq:"≰",nleqq:"≦̸",nleqslant:"⩽̸",nles:"⩽̸",nless:"≮",nLl:"⋘̸",nlsim:"≴",nLt:"≪⃒",nlt:"≮",nltri:"⋪",nltrie:"⋬",nLtv:"≪̸",nmid:"∤",NoBreak:"⁠",NonBreakingSpace:" ",nopf:"𝕟",Nopf:"ℕ",Not:"⫬",not:"¬",NotCongruent:"≢",NotCupCap:"≭",NotDoubleVerticalBar:"∦",NotElement:"∉",NotEqual:"≠",NotEqualTilde:"≂̸",NotExists:"∄",NotGreater:"≯",NotGreaterEqual:"≱",NotGreaterFullEqual:"≧̸",NotGreaterGreater:"≫̸",NotGreaterLess:"≹",NotGreaterSlantEqual:"⩾̸",NotGreaterTilde:"≵",NotHumpDownHump:"≎̸",NotHumpEqual:"≏̸",notin:"∉",notindot:"⋵̸",notinE:"⋹̸",notinva:"∉",notinvb:"⋷",notinvc:"⋶",NotLeftTriangleBar:"⧏̸",NotLeftTriangle:"⋪",NotLeftTriangleEqual:"⋬",NotLess:"≮",NotLessEqual:"≰",NotLessGreater:"≸",NotLessLess:"≪̸",NotLessSlantEqual:"⩽̸",NotLessTilde:"≴",NotNestedGreaterGreater:"⪢̸",NotNestedLessLess:"⪡̸",notni:"∌",notniva:"∌",notnivb:"⋾",notnivc:"⋽",NotPrecedes:"⊀",NotPrecedesEqual:"⪯̸",NotPrecedesSlantEqual:"⋠",NotReverseElement:"∌",NotRightTriangleBar:"⧐̸",NotRightTriangle:"⋫",NotRightTriangleEqual:"⋭",NotSquareSubset:"⊏̸",NotSquareSubsetEqual:"⋢",NotSquareSuperset:"⊐̸",NotSquareSupersetEqual:"⋣",NotSubset:"⊂⃒",NotSubsetEqual:"⊈",NotSucceeds:"⊁",NotSucceedsEqual:"⪰̸",NotSucceedsSlantEqual:"⋡",NotSucceedsTilde:"≿̸",NotSuperset:"⊃⃒",NotSupersetEqual:"⊉",NotTilde:"≁",NotTildeEqual:"≄",NotTildeFullEqual:"≇",NotTildeTilde:"≉",NotVerticalBar:"∤",nparallel:"∦",npar:"∦",nparsl:"⫽⃥",npart:"∂̸",npolint:"⨔",npr:"⊀",nprcue:"⋠",nprec:"⊀",npreceq:"⪯̸",npre:"⪯̸",nrarrc:"⤳̸",nrarr:"↛",nrArr:"⇏",nrarrw:"↝̸",nrightarrow:"↛",nRightarrow:"⇏",nrtri:"⋫",nrtrie:"⋭",nsc:"⊁",nsccue:"⋡",nsce:"⪰̸",Nscr:"𝒩",nscr:"𝓃",nshortmid:"∤",nshortparallel:"∦",nsim:"≁",nsime:"≄",nsimeq:"≄",nsmid:"∤",nspar:"∦",nsqsube:"⋢",nsqsupe:"⋣",nsub:"⊄",nsubE:"⫅̸",nsube:"⊈",nsubset:"⊂⃒",nsubseteq:"⊈",nsubseteqq:"⫅̸",nsucc:"⊁",nsucceq:"⪰̸",nsup:"⊅",nsupE:"⫆̸",nsupe:"⊉",nsupset:"⊃⃒",nsupseteq:"⊉",nsupseteqq:"⫆̸",ntgl:"≹",Ntilde:"Ñ",ntilde:"ñ",ntlg:"≸",ntriangleleft:"⋪",ntrianglelefteq:"⋬",ntriangleright:"⋫",ntrianglerighteq:"⋭",Nu:"Ν",nu:"ν",num:"#",numero:"№",numsp:" ",nvap:"≍⃒",nvdash:"⊬",nvDash:"⊭",nVdash:"⊮",nVDash:"⊯",nvge:"≥⃒",nvgt:">⃒",nvHarr:"⤄",nvinfin:"⧞",nvlArr:"⤂",nvle:"≤⃒",nvlt:"<⃒",nvltrie:"⊴⃒",nvrArr:"⤃",nvrtrie:"⊵⃒",nvsim:"∼⃒",nwarhk:"⤣",nwarr:"↖",nwArr:"⇖",nwarrow:"↖",nwnear:"⤧",Oacute:"Ó",oacute:"ó",oast:"⊛",Ocirc:"Ô",ocirc:"ô",ocir:"⊚",Ocy:"О",ocy:"о",odash:"⊝",Odblac:"Ő",odblac:"ő",odiv:"⨸",odot:"⊙",odsold:"⦼",OElig:"Œ",oelig:"œ",ofcir:"⦿",Ofr:"𝔒",ofr:"𝔬",ogon:"˛",Ograve:"Ò",ograve:"ò",ogt:"⧁",ohbar:"⦵",ohm:"Ω",oint:"∮",olarr:"↺",olcir:"⦾",olcross:"⦻",oline:"‾",olt:"⧀",Omacr:"Ō",omacr:"ō",Omega:"Ω",omega:"ω",Omicron:"Ο",omicron:"ο",omid:"⦶",ominus:"⊖",Oopf:"𝕆",oopf:"𝕠",opar:"⦷",OpenCurlyDoubleQuote:"“",OpenCurlyQuote:"‘",operp:"⦹",oplus:"⊕",orarr:"↻",Or:"⩔",or:"∨",ord:"⩝",order:"ℴ",orderof:"ℴ",ordf:"ª",ordm:"º",origof:"⊶",oror:"⩖",orslope:"⩗",orv:"⩛",oS:"Ⓢ",Oscr:"𝒪",oscr:"ℴ",Oslash:"Ø",oslash:"ø",osol:"⊘",Otilde:"Õ",otilde:"õ",otimesas:"⨶",Otimes:"⨷",otimes:"⊗",Ouml:"Ö",ouml:"ö",ovbar:"⌽",OverBar:"‾",OverBrace:"⏞",OverBracket:"⎴",OverParenthesis:"⏜",para:"¶",parallel:"∥",par:"∥",parsim:"⫳",parsl:"⫽",part:"∂",PartialD:"∂",Pcy:"П",pcy:"п",percnt:"%",period:".",permil:"‰",perp:"⊥",pertenk:"‱",Pfr:"𝔓",pfr:"𝔭",Phi:"Φ",phi:"φ",phiv:"ϕ",phmmat:"ℳ",phone:"☎",Pi:"Π",pi:"π",pitchfork:"⋔",piv:"ϖ",planck:"ℏ",planckh:"ℎ",plankv:"ℏ",plusacir:"⨣",plusb:"⊞",pluscir:"⨢",plus:"+",plusdo:"∔",plusdu:"⨥",pluse:"⩲",PlusMinus:"±",plusmn:"±",plussim:"⨦",plustwo:"⨧",pm:"±",Poincareplane:"ℌ",pointint:"⨕",popf:"𝕡",Popf:"ℙ",pound:"£",prap:"⪷",Pr:"⪻",pr:"≺",prcue:"≼",precapprox:"⪷",prec:"≺",preccurlyeq:"≼",Precedes:"≺",PrecedesEqual:"⪯",PrecedesSlantEqual:"≼",PrecedesTilde:"≾",preceq:"⪯",precnapprox:"⪹",precneqq:"⪵",precnsim:"⋨",pre:"⪯",prE:"⪳",precsim:"≾",prime:"′",Prime:"″",primes:"ℙ",prnap:"⪹",prnE:"⪵",prnsim:"⋨",prod:"∏",Product:"∏",profalar:"⌮",profline:"⌒",profsurf:"⌓",prop:"∝",Proportional:"∝",Proportion:"∷",propto:"∝",prsim:"≾",prurel:"⊰",Pscr:"𝒫",pscr:"𝓅",Psi:"Ψ",psi:"ψ",puncsp:" ",Qfr:"𝔔",qfr:"𝔮",qint:"⨌",qopf:"𝕢",Qopf:"ℚ",qprime:"⁗",Qscr:"𝒬",qscr:"𝓆",quaternions:"ℍ",quatint:"⨖",quest:"?",questeq:"≟",quot:'"',QUOT:'"',rAarr:"⇛",race:"∽̱",Racute:"Ŕ",racute:"ŕ",radic:"√",raemptyv:"⦳",rang:"⟩",Rang:"⟫",rangd:"⦒",range:"⦥",rangle:"⟩",raquo:"»",rarrap:"⥵",rarrb:"⇥",rarrbfs:"⤠",rarrc:"⤳",rarr:"→",Rarr:"↠",rArr:"⇒",rarrfs:"⤞",rarrhk:"↪",rarrlp:"↬",rarrpl:"⥅",rarrsim:"⥴",Rarrtl:"⤖",rarrtl:"↣",rarrw:"↝",ratail:"⤚",rAtail:"⤜",ratio:"∶",rationals:"ℚ",rbarr:"⤍",rBarr:"⤏",RBarr:"⤐",rbbrk:"❳",rbrace:"}",rbrack:"]",rbrke:"⦌",rbrksld:"⦎",rbrkslu:"⦐",Rcaron:"Ř",rcaron:"ř",Rcedil:"Ŗ",rcedil:"ŗ",rceil:"⌉",rcub:"}",Rcy:"Р",rcy:"р",rdca:"⤷",rdldhar:"⥩",rdquo:"”",rdquor:"”",rdsh:"↳",real:"ℜ",realine:"ℛ",realpart:"ℜ",reals:"ℝ",Re:"ℜ",rect:"▭",reg:"®",REG:"®",ReverseElement:"∋",ReverseEquilibrium:"⇋",ReverseUpEquilibrium:"⥯",rfisht:"⥽",rfloor:"⌋",rfr:"𝔯",Rfr:"ℜ",rHar:"⥤",rhard:"⇁",rharu:"⇀",rharul:"⥬",Rho:"Ρ",rho:"ρ",rhov:"ϱ",RightAngleBracket:"⟩",RightArrowBar:"⇥",rightarrow:"→",RightArrow:"→",Rightarrow:"⇒",RightArrowLeftArrow:"⇄",rightarrowtail:"↣",RightCeiling:"⌉",RightDoubleBracket:"⟧",RightDownTeeVector:"⥝",RightDownVectorBar:"⥕",RightDownVector:"⇂",RightFloor:"⌋",rightharpoondown:"⇁",rightharpoonup:"⇀",rightleftarrows:"⇄",rightleftharpoons:"⇌",rightrightarrows:"⇉",rightsquigarrow:"↝",RightTeeArrow:"↦",RightTee:"⊢",RightTeeVector:"⥛",rightthreetimes:"⋌",RightTriangleBar:"⧐",RightTriangle:"⊳",RightTriangleEqual:"⊵",RightUpDownVector:"⥏",RightUpTeeVector:"⥜",RightUpVectorBar:"⥔",RightUpVector:"↾",RightVectorBar:"⥓",RightVector:"⇀",ring:"˚",risingdotseq:"≓",rlarr:"⇄",rlhar:"⇌",rlm:"‏",rmoustache:"⎱",rmoust:"⎱",rnmid:"⫮",roang:"⟭",roarr:"⇾",robrk:"⟧",ropar:"⦆",ropf:"𝕣",Ropf:"ℝ",roplus:"⨮",rotimes:"⨵",RoundImplies:"⥰",rpar:")",rpargt:"⦔",rppolint:"⨒",rrarr:"⇉",Rrightarrow:"⇛",rsaquo:"›",rscr:"𝓇",Rscr:"ℛ",rsh:"↱",Rsh:"↱",rsqb:"]",rsquo:"’",rsquor:"’",rthree:"⋌",rtimes:"⋊",rtri:"▹",rtrie:"⊵",rtrif:"▸",rtriltri:"⧎",RuleDelayed:"⧴",ruluhar:"⥨",rx:"℞",Sacute:"Ś",sacute:"ś",sbquo:"‚",scap:"⪸",Scaron:"Š",scaron:"š",Sc:"⪼",sc:"≻",sccue:"≽",sce:"⪰",scE:"⪴",Scedil:"Ş",scedil:"ş",Scirc:"Ŝ",scirc:"ŝ",scnap:"⪺",scnE:"⪶",scnsim:"⋩",scpolint:"⨓",scsim:"≿",Scy:"С",scy:"с",sdotb:"⊡",sdot:"⋅",sdote:"⩦",searhk:"⤥",searr:"↘",seArr:"⇘",searrow:"↘",sect:"§",semi:";",seswar:"⤩",setminus:"∖",setmn:"∖",sext:"✶",Sfr:"𝔖",sfr:"𝔰",sfrown:"⌢",sharp:"♯",SHCHcy:"Щ",shchcy:"щ",SHcy:"Ш",shcy:"ш",ShortDownArrow:"↓",ShortLeftArrow:"←",shortmid:"∣",shortparallel:"∥",ShortRightArrow:"→",ShortUpArrow:"↑",shy:"­",Sigma:"Σ",sigma:"σ",sigmaf:"ς",sigmav:"ς",sim:"∼",simdot:"⩪",sime:"≃",simeq:"≃",simg:"⪞",simgE:"⪠",siml:"⪝",simlE:"⪟",simne:"≆",simplus:"⨤",simrarr:"⥲",slarr:"←",SmallCircle:"∘",smallsetminus:"∖",smashp:"⨳",smeparsl:"⧤",smid:"∣",smile:"⌣",smt:"⪪",smte:"⪬",smtes:"⪬︀",SOFTcy:"Ь",softcy:"ь",solbar:"⌿",solb:"⧄",sol:"/",Sopf:"𝕊",sopf:"𝕤",spades:"♠",spadesuit:"♠",spar:"∥",sqcap:"⊓",sqcaps:"⊓︀",sqcup:"⊔",sqcups:"⊔︀",Sqrt:"√",sqsub:"⊏",sqsube:"⊑",sqsubset:"⊏",sqsubseteq:"⊑",sqsup:"⊐",sqsupe:"⊒",sqsupset:"⊐",sqsupseteq:"⊒",square:"□",Square:"□",SquareIntersection:"⊓",SquareSubset:"⊏",SquareSubsetEqual:"⊑",SquareSuperset:"⊐",SquareSupersetEqual:"⊒",SquareUnion:"⊔",squarf:"▪",squ:"□",squf:"▪",srarr:"→",Sscr:"𝒮",sscr:"𝓈",ssetmn:"∖",ssmile:"⌣",sstarf:"⋆",Star:"⋆",star:"☆",starf:"★",straightepsilon:"ϵ",straightphi:"ϕ",strns:"¯",sub:"⊂",Sub:"⋐",subdot:"⪽",subE:"⫅",sube:"⊆",subedot:"⫃",submult:"⫁",subnE:"⫋",subne:"⊊",subplus:"⪿",subrarr:"⥹",subset:"⊂",Subset:"⋐",subseteq:"⊆",subseteqq:"⫅",SubsetEqual:"⊆",subsetneq:"⊊",subsetneqq:"⫋",subsim:"⫇",subsub:"⫕",subsup:"⫓",succapprox:"⪸",succ:"≻",succcurlyeq:"≽",Succeeds:"≻",SucceedsEqual:"⪰",SucceedsSlantEqual:"≽",SucceedsTilde:"≿",succeq:"⪰",succnapprox:"⪺",succneqq:"⪶",succnsim:"⋩",succsim:"≿",SuchThat:"∋",sum:"∑",Sum:"∑",sung:"♪",sup1:"¹",sup2:"²",sup3:"³",sup:"⊃",Sup:"⋑",supdot:"⪾",supdsub:"⫘",supE:"⫆",supe:"⊇",supedot:"⫄",Superset:"⊃",SupersetEqual:"⊇",suphsol:"⟉",suphsub:"⫗",suplarr:"⥻",supmult:"⫂",supnE:"⫌",supne:"⊋",supplus:"⫀",supset:"⊃",Supset:"⋑",supseteq:"⊇",supseteqq:"⫆",supsetneq:"⊋",supsetneqq:"⫌",supsim:"⫈",supsub:"⫔",supsup:"⫖",swarhk:"⤦",swarr:"↙",swArr:"⇙",swarrow:"↙",swnwar:"⤪",szlig:"ß",Tab:"\t",target:"⌖",Tau:"Τ",tau:"τ",tbrk:"⎴",Tcaron:"Ť",tcaron:"ť",Tcedil:"Ţ",tcedil:"ţ",Tcy:"Т",tcy:"т",tdot:"⃛",telrec:"⌕",Tfr:"𝔗",tfr:"𝔱",there4:"∴",therefore:"∴",Therefore:"∴",Theta:"Θ",theta:"θ",thetasym:"ϑ",thetav:"ϑ",thickapprox:"≈",thicksim:"∼",ThickSpace:"  ",ThinSpace:" ",thinsp:" ",thkap:"≈",thksim:"∼",THORN:"Þ",thorn:"þ",tilde:"˜",Tilde:"∼",TildeEqual:"≃",TildeFullEqual:"≅",TildeTilde:"≈",timesbar:"⨱",timesb:"⊠",times:"×",timesd:"⨰",tint:"∭",toea:"⤨",topbot:"⌶",topcir:"⫱",top:"⊤",Topf:"𝕋",topf:"𝕥",topfork:"⫚",tosa:"⤩",tprime:"‴",trade:"™",TRADE:"™",triangle:"▵",triangledown:"▿",triangleleft:"◃",trianglelefteq:"⊴",triangleq:"≜",triangleright:"▹",trianglerighteq:"⊵",tridot:"◬",trie:"≜",triminus:"⨺",TripleDot:"⃛",triplus:"⨹",trisb:"⧍",tritime:"⨻",trpezium:"⏢",Tscr:"𝒯",tscr:"𝓉",TScy:"Ц",tscy:"ц",TSHcy:"Ћ",tshcy:"ћ",Tstrok:"Ŧ",tstrok:"ŧ",twixt:"≬",twoheadleftarrow:"↞",twoheadrightarrow:"↠",Uacute:"Ú",uacute:"ú",uarr:"↑",Uarr:"↟",uArr:"⇑",Uarrocir:"⥉",Ubrcy:"Ў",ubrcy:"ў",Ubreve:"Ŭ",ubreve:"ŭ",Ucirc:"Û",ucirc:"û",Ucy:"У",ucy:"у",udarr:"⇅",Udblac:"Ű",udblac:"ű",udhar:"⥮",ufisht:"⥾",Ufr:"𝔘",ufr:"𝔲",Ugrave:"Ù",ugrave:"ù",uHar:"⥣",uharl:"↿",uharr:"↾",uhblk:"▀",ulcorn:"⌜",ulcorner:"⌜",ulcrop:"⌏",ultri:"◸",Umacr:"Ū",umacr:"ū",uml:"¨",UnderBar:"_",UnderBrace:"⏟",UnderBracket:"⎵",UnderParenthesis:"⏝",Union:"⋃",UnionPlus:"⊎",Uogon:"Ų",uogon:"ų",Uopf:"𝕌",uopf:"𝕦",UpArrowBar:"⤒",uparrow:"↑",UpArrow:"↑",Uparrow:"⇑",UpArrowDownArrow:"⇅",updownarrow:"↕",UpDownArrow:"↕",Updownarrow:"⇕",UpEquilibrium:"⥮",upharpoonleft:"↿",upharpoonright:"↾",uplus:"⊎",UpperLeftArrow:"↖",UpperRightArrow:"↗",upsi:"υ",Upsi:"ϒ",upsih:"ϒ",Upsilon:"Υ",upsilon:"υ",UpTeeArrow:"↥",UpTee:"⊥",upuparrows:"⇈",urcorn:"⌝",urcorner:"⌝",urcrop:"⌎",Uring:"Ů",uring:"ů",urtri:"◹",Uscr:"𝒰",uscr:"𝓊",utdot:"⋰",Utilde:"Ũ",utilde:"ũ",utri:"▵",utrif:"▴",uuarr:"⇈",Uuml:"Ü",uuml:"ü",uwangle:"⦧",vangrt:"⦜",varepsilon:"ϵ",varkappa:"ϰ",varnothing:"∅",varphi:"ϕ",varpi:"ϖ",varpropto:"∝",varr:"↕",vArr:"⇕",varrho:"ϱ",varsigma:"ς",varsubsetneq:"⊊︀",varsubsetneqq:"⫋︀",varsupsetneq:"⊋︀",varsupsetneqq:"⫌︀",vartheta:"ϑ",vartriangleleft:"⊲",vartriangleright:"⊳",vBar:"⫨",Vbar:"⫫",vBarv:"⫩",Vcy:"В",vcy:"в",vdash:"⊢",vDash:"⊨",Vdash:"⊩",VDash:"⊫",Vdashl:"⫦",veebar:"⊻",vee:"∨",Vee:"⋁",veeeq:"≚",vellip:"⋮",verbar:"|",Verbar:"‖",vert:"|",Vert:"‖",VerticalBar:"∣",VerticalLine:"|",VerticalSeparator:"❘",VerticalTilde:"≀",VeryThinSpace:" ",Vfr:"𝔙",vfr:"𝔳",vltri:"⊲",vnsub:"⊂⃒",vnsup:"⊃⃒",Vopf:"𝕍",vopf:"𝕧",vprop:"∝",vrtri:"⊳",Vscr:"𝒱",vscr:"𝓋",vsubnE:"⫋︀",vsubne:"⊊︀",vsupnE:"⫌︀",vsupne:"⊋︀",Vvdash:"⊪",vzigzag:"⦚",Wcirc:"Ŵ",wcirc:"ŵ",wedbar:"⩟",wedge:"∧",Wedge:"⋀",wedgeq:"≙",weierp:"℘",Wfr:"𝔚",wfr:"𝔴",Wopf:"𝕎",wopf:"𝕨",wp:"℘",wr:"≀",wreath:"≀",Wscr:"𝒲",wscr:"𝓌",xcap:"⋂",xcirc:"◯",xcup:"⋃",xdtri:"▽",Xfr:"𝔛",xfr:"𝔵",xharr:"⟷",xhArr:"⟺",Xi:"Ξ",xi:"ξ",xlarr:"⟵",xlArr:"⟸",xmap:"⟼",xnis:"⋻",xodot:"⨀",Xopf:"𝕏",xopf:"𝕩",xoplus:"⨁",xotime:"⨂",xrarr:"⟶",xrArr:"⟹",Xscr:"𝒳",xscr:"𝓍",xsqcup:"⨆",xuplus:"⨄",xutri:"△",xvee:"⋁",xwedge:"⋀",Yacute:"Ý",yacute:"ý",YAcy:"Я",yacy:"я",Ycirc:"Ŷ",ycirc:"ŷ",Ycy:"Ы",ycy:"ы",yen:"¥",Yfr:"𝔜",yfr:"𝔶",YIcy:"Ї",yicy:"ї",Yopf:"𝕐",yopf:"𝕪",Yscr:"𝒴",yscr:"𝓎",YUcy:"Ю",yucy:"ю",yuml:"ÿ",Yuml:"Ÿ",Zacute:"Ź",zacute:"ź",Zcaron:"Ž",zcaron:"ž",Zcy:"З",zcy:"з",Zdot:"Ż",zdot:"ż",zeetrf:"ℨ",ZeroWidthSpace:"​",Zeta:"Ζ",zeta:"ζ",zfr:"𝔷",Zfr:"ℨ",ZHcy:"Ж",zhcy:"ж",zigrarr:"⇝",zopf:"𝕫",Zopf:"ℤ",Zscr:"𝒵",zscr:"𝓏",zwj:"‍",zwnj:"‌"},Qh=/[!-#%-\*,-\/:;\?@\[-\]_\{\}\xA1\xA7\xAB\xB6\xB7\xBB\xBF\u037E\u0387\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u09FD\u0A76\u0AF0\u0C84\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F14\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1360-\u1368\u1400\u166D\u166E\u169B\u169C\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CC0-\u1CC7\u1CD3\u2010-\u2027\u2030-\u2043\u2045-\u2051\u2053-\u205E\u207D\u207E\u208D\u208E\u2308-\u230B\u2329\u232A\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30-\u2E4E\u3001-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA8FC\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uAAF0\uAAF1\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uFF3F\uFF5B\uFF5D\uFF5F-\uFF65]|\uD800[\uDD00-\uDD02\uDF9F\uDFD0]|\uD801\uDD6F|\uD802[\uDC57\uDD1F\uDD3F\uDE50-\uDE58\uDE7F\uDEF0-\uDEF6\uDF39-\uDF3F\uDF99-\uDF9C]|\uD803[\uDF55-\uDF59]|\uD804[\uDC47-\uDC4D\uDCBB\uDCBC\uDCBE-\uDCC1\uDD40-\uDD43\uDD74\uDD75\uDDC5-\uDDC8\uDDCD\uDDDB\uDDDD-\uDDDF\uDE38-\uDE3D\uDEA9]|\uD805[\uDC4B-\uDC4F\uDC5B\uDC5D\uDCC6\uDDC1-\uDDD7\uDE41-\uDE43\uDE60-\uDE6C\uDF3C-\uDF3E]|\uD806[\uDC3B\uDE3F-\uDE46\uDE9A-\uDE9C\uDE9E-\uDEA2]|\uD807[\uDC41-\uDC45\uDC70\uDC71\uDEF7\uDEF8]|\uD809[\uDC70-\uDC74]|\uD81A[\uDE6E\uDE6F\uDEF5\uDF37-\uDF3B\uDF44]|\uD81B[\uDE97-\uDE9A]|\uD82F\uDC9F|\uD836[\uDE87-\uDE8B]|\uD83A[\uDD5E\uDD5F]/,Xh={},Yh={};function Jh(e){var t,n,r=Yh[e];if(r)return r;for(r=Yh[e]=[],t=0;t<128;t++)n=String.fromCharCode(t),/^[0-9a-z]$/i.test(n)?r.push(n):r.push("%"+("0"+t.toString(16).toUpperCase()).slice(-2));for(t=0;t=55296&&o<=57343){if(o>=55296&&o<=56319&&r+1=56320&&a<=57343){l+=encodeURIComponent(e[r]+e[r+1]),r++;continue}l+="%EF%BF%BD"}else l+=encodeURIComponent(e[r]);return l}g(Jh,"getEncodeCache"),g(Zh,"encode$1"),Zh.defaultChars=";/?:@&=+$,-_.!~*'()#",Zh.componentChars="-_.!~*'()";var em=Zh,tm={};function nm(e){var t,n,r=tm[e];if(r)return r;for(r=tm[e]=[],t=0;t<128;t++)n=String.fromCharCode(t),r.push(n);for(t=0;t=55296&&l<=57343?"���":String.fromCharCode(l),t+=6):240==(248&i)&&t+91114111?u+="����":(l-=65536,u+=String.fromCharCode(55296+(l>>10),56320+(1023&l))),t+=9):u+="�";return u}))}g(nm,"getDecodeCache"),g(rm,"decode$1"),rm.defaultChars=";/?:@&=+$,#",rm.componentChars="";var im=rm,om=g((function(e){var t="";return t+=e.protocol||"",t+=e.slashes?"//":"",t+=e.auth?e.auth+"@":"",e.hostname&&-1!==e.hostname.indexOf(":")?t+="["+e.hostname+"]":t+=e.hostname||"",t+=e.port?":"+e.port:"",t+=e.pathname||"",(t+=e.search||"")+(e.hash||"")}),"format");function am(){this.protocol=null,this.slashes=null,this.auth=null,this.port=null,this.hostname=null,this.hash=null,this.search=null,this.pathname=null}g(am,"Url");var sm=/^([a-z0-9.+-]+:)/i,lm=/:[0-9]*$/,um=/^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/,cm=["{","}","|","\\","^","`"].concat(["<",">",'"',"`"," ","\r","\n","\t"]),dm=["'"].concat(cm),fm=["%","/","?",";","#"].concat(dm),pm=["/","?","#"],hm=/^[+a-z0-9A-Z_-]{0,63}$/,mm=/^([+a-z0-9A-Z_-]{0,63})(.*)$/,gm={javascript:!0,"javascript:":!0},vm={http:!0,https:!0,ftp:!0,gopher:!0,file:!0,"http:":!0,"https:":!0,"ftp:":!0,"gopher:":!0,"file:":!0};function ym(e,t){if(e&&e instanceof am)return e;var n=new am;return n.parse(e,t),n}g(ym,"urlParse"),am.prototype.parse=function(e,t){var n,r,i,o,a,s=e;if(s=s.trim(),!t&&1===e.split("#").length){var l=um.exec(s);if(l)return this.pathname=l[1],l[2]&&(this.search=l[2]),this}var u=sm.exec(s);if(u&&(i=(u=u[0]).toLowerCase(),this.protocol=u,s=s.substr(u.length)),(t||u||s.match(/^\/\/[^@\/]+@[^@\/]+/))&&(!(a="//"===s.substr(0,2))||u&&gm[u]||(s=s.substr(2),this.slashes=!0)),!gm[u]&&(a||u&&!vm[u])){var c,d,f=-1;for(n=0;n127?v+="x":v+=g[y];if(!v.match(hm)){var E=m.slice(0,n),T=m.slice(n+1),w=g.match(mm);w&&(E.push(w[1]),T.unshift(w[2])),T.length&&(s=T.join(".")+s),this.hostname=E.join(".");break}}}}this.hostname.length>255&&(this.hostname=""),h&&(this.hostname=this.hostname.substr(1,this.hostname.length-2))}var C=s.indexOf("#");-1!==C&&(this.hash=s.substr(C),s=s.slice(0,C));var S=s.indexOf("?");return-1!==S&&(this.search=s.substr(S),s=s.slice(0,S)),s&&(this.pathname=s),vm[i]&&this.hostname&&!this.pathname&&(this.pathname=""),this},am.prototype.parseHost=function(e){var t=lm.exec(e);t&&(":"!==(t=t[0])&&(this.port=t.substr(1)),e=e.substr(0,e.length-t.length)),e&&(this.hostname=e)};var bm=ym;Xh.encode=em,Xh.decode=im,Xh.format=om,Xh.parse=bm;var Em={},Tm=/[\0-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/,wm=/[\0-\x1F\x7F-\x9F]/,Cm=/[ \xA0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000]/;Em.Any=Tm,Em.Cc=wm,Em.Cf=/[\xAD\u0600-\u0605\u061C\u06DD\u070F\u08E2\u180E\u200B-\u200F\u202A-\u202E\u2060-\u2064\u2066-\u206F\uFEFF\uFFF9-\uFFFB]|\uD804[\uDCBD\uDCCD]|\uD82F[\uDCA0-\uDCA3]|\uD834[\uDD73-\uDD7A]|\uDB40[\uDC01\uDC20-\uDC7F]/,Em.P=Qh,Em.Z=Cm,function(e){function t(e){return Object.prototype.toString.call(e)}function n(e){return"[object String]"===t(e)}g(t,"_class"),g(n,"isString");var r=Object.prototype.hasOwnProperty;function i(e,t){return r.call(e,t)}function o(e){return Array.prototype.slice.call(arguments,1).forEach((function(t){if(t){if("object"!=typeof t)throw new TypeError(t+"must be object");Object.keys(t).forEach((function(n){e[n]=t[n]}))}})),e}function a(e,t,n){return[].concat(e.slice(0,t),n,e.slice(t+1))}function s(e){return!(e>=55296&&e<=57343||e>=64976&&e<=65007||65535==(65535&e)||65534==(65535&e)||e>=0&&e<=8||11===e||e>=14&&e<=31||e>=127&&e<=159||e>1114111)}function l(e){if(e>65535){var t=55296+((e-=65536)>>10),n=56320+(1023&e);return String.fromCharCode(t,n)}return String.fromCharCode(e)}g(i,"has"),g(o,"assign"),g(a,"arrayReplaceAt"),g(s,"isValidEntityCode"),g(l,"fromCodePoint");var u=/\\([!"#$%&'()*+,\-.\/:;<=>?@[\\\]^_`{|}~])/g,c=new RegExp(u.source+"|"+/&([a-z#][a-z0-9]{1,31});/gi.source,"gi"),d=/^#((?:x[a-f0-9]{1,8}|[0-9]{1,8}))/i,f=Kh;function p(e,t){var n=0;return i(f,t)?f[t]:35===t.charCodeAt(0)&&d.test(t)&&s(n="x"===t[1].toLowerCase()?parseInt(t.slice(2),16):parseInt(t.slice(1),10))?l(n):e}function h(e){return e.indexOf("\\")<0?e:e.replace(u,"$1")}function m(e){return e.indexOf("\\")<0&&e.indexOf("&")<0?e:e.replace(c,(function(e,t,n){return t||p(e,n)}))}g(p,"replaceEntityPattern"),g(h,"unescapeMd"),g(m,"unescapeAll");var v=/[&<>"]/,y=/[&<>"]/g,b={"&":"&","<":"<",">":">",'"':"""};function E(e){return b[e]}function T(e){return v.test(e)?e.replace(y,E):e}g(E,"replaceUnsafeChar"),g(T,"escapeHtml");var w=/[.?*+^$[\]\\(){}|-]/g;function C(e){return e.replace(w,"\\$&")}function S(e){switch(e){case 9:case 32:return!0}return!1}function x(e){if(e>=8192&&e<=8202)return!0;switch(e){case 9:case 10:case 11:case 12:case 13:case 32:case 160:case 5760:case 8239:case 8287:case 12288:return!0}return!1}g(C,"escapeRE"),g(S,"isSpace"),g(x,"isWhiteSpace");var k=Qh;function N(e){return k.test(e)}function _(e){switch(e){case 33:case 34:case 35:case 36:case 37:case 38:case 39:case 40:case 41:case 42:case 43:case 44:case 45:case 46:case 47:case 58:case 59:case 60:case 61:case 62:case 63:case 64:case 91:case 92:case 93:case 94:case 95:case 96:case 123:case 124:case 125:case 126:return!0;default:return!1}}function O(e){return e=e.trim().replace(/\s+/g," "),"Ṿ"==="ẞ".toLowerCase()&&(e=e.replace(/ẞ/g,"ß")),e.toLowerCase().toUpperCase()}g(N,"isPunctChar"),g(_,"isMdAsciiPunct"),g(O,"normalizeReference"),e.lib={},e.lib.mdurl=Xh,e.lib.ucmicro=Em,e.assign=o,e.isString=n,e.has=i,e.unescapeMd=h,e.unescapeAll=m,e.isValidEntityCode=s,e.fromCodePoint=l,e.escapeHtml=T,e.arrayReplaceAt=a,e.isSpace=S,e.isWhiteSpace=x,e.isMdAsciiPunct=_,e.isPunctChar=N,e.escapeRE=C,e.normalizeReference=O}(Wh);var Sm={},xm=g((function(e,t,n){var r,i,o,a,s=-1,l=e.posMax,u=e.pos;for(e.pos=t+1,r=1;e.pos32)return a;if(41===r){if(0===i)break;i--}t++}return o===t||0!==i||(a.str=km(e.slice(o,t)),a.lines=0,a.pos=t,a.ok=!0),a}),"parseLinkDestination"),_m=Wh.unescapeAll,Om=g((function(e,t,n){var r,i,o=0,a=t,s={ok:!1,pos:0,lines:0,str:""};if(t>=n)return s;if(34!==(i=e.charCodeAt(t))&&39!==i&&40!==i)return s;for(t++,40===i&&(i=41);t"+Lm(e[t].content)+""},Am.code_block=function(e,t,n,r,i){var o=e[t];return""+Lm(e[t].content)+"\n"},Am.fence=function(e,t,n,r,i){var o,a,s,l,u,c=e[t],d=c.info?Dm(c.info).trim():"",f="",p="";return d&&(f=(s=d.split(/(\s+)/g))[0],p=s.slice(2).join("")),0===(o=n.highlight&&n.highlight(c.content,f,p)||Lm(c.content)).indexOf(""+o+"\n"):"
"+o+"
\n"},Am.image=function(e,t,n,r,i){var o=e[t];return o.attrs[o.attrIndex("alt")][1]=i.renderInlineAsText(o.children,n,r),i.renderToken(e,t,n)},Am.hardbreak=function(e,t,n){return n.xhtmlOut?"
\n":"
\n"},Am.softbreak=function(e,t,n){return n.breaks?n.xhtmlOut?"
\n":"
\n":"\n"},Am.text=function(e,t){return Lm(e[t].content)},Am.html_block=function(e,t){return e[t].content},Am.html_inline=function(e,t){return e[t].content},g(Mm,"Renderer$1"),Mm.prototype.renderAttrs=g((function(e){var t,n,r;if(!e.attrs)return"";for(r="",t=0,n=e.attrs.length;t\n":">")}),"renderToken"),Mm.prototype.renderInline=function(e,t,n){for(var r,i="",o=this.rules,a=0,s=e.length;a\s]/i.test(e)}function Gm(e){return/^<\/a\s*>/i.test(e)}g(Hm,"isLinkOpen"),g(Gm,"isLinkClose");var zm=g((function(e){var t,n,r,i,o,a,s,l,u,c,d,f,p,h,m,g,v,y=e.tokens;if(e.md.options.linkify)for(n=0,r=y.length;n=0;t--)if("link_close"!==(a=i[t]).type){if("html_inline"===a.type&&(Hm(a.content)&&p>0&&p--,Gm(a.content)&&p++),!(p>0)&&"text"===a.type&&e.md.linkify.test(a.content)){for(u=a.content,v=e.md.linkify.match(u),s=[],f=a.level,d=0,l=0;ld&&((o=new e.Token("text","",0)).content=u.slice(d,c),o.level=f,s.push(o)),(o=new e.Token("link_open","a",1)).attrs=[["href",m]],o.level=f++,o.markup="linkify",o.info="auto",s.push(o),(o=new e.Token("text","",0)).content=g,o.level=f,s.push(o),(o=new e.Token("link_close","a",-1)).level=--f,o.markup="linkify",o.info="auto",s.push(o),d=v[l].lastIndex);d=0;t--)"text"!==(n=e[t]).type||r||(n.content=n.content.replace(Qm,Ym)),"link_open"===n.type&&"auto"===n.info&&r--,"link_close"===n.type&&"auto"===n.info&&r++}function Zm(e){var t,n,r=0;for(t=e.length-1;t>=0;t--)"text"!==(n=e[t]).type||r||Wm.test(n.content)&&(n.content=n.content.replace(/\+-/g,"±").replace(/\.{2,}/g,"…").replace(/([?!])…/g,"$1..").replace(/([?!]){4,}/g,"$1$1$1").replace(/,{2,}/g,",").replace(/(^|[^-])---(?=[^-]|$)/gm,"$1—").replace(/(^|\s)--(?=\s|$)/gm,"$1–").replace(/(^|[^-\s])--(?=[^-\s]|$)/gm,"$1–")),"link_open"===n.type&&"auto"===n.info&&r--,"link_close"===n.type&&"auto"===n.info&&r++}g(Ym,"replaceFn"),g(Jm,"replace_scoped"),g(Zm,"replace_rare");var eg=g((function(e){var t;if(e.md.options.typographer)for(t=e.tokens.length-1;t>=0;t--)"inline"===e.tokens[t].type&&(Km.test(e.tokens[t].content)&&Jm(e.tokens[t].children),Wm.test(e.tokens[t].content)&&Zm(e.tokens[t].children))}),"replace"),tg=Wh.isWhiteSpace,ng=Wh.isPunctChar,rg=Wh.isMdAsciiPunct,ig=/['"]/,og=/['"]/g,ag="’";function sg(e,t,n){return e.substr(0,t)+n+e.substr(t+1)}function lg(e,t){var n,r,i,o,a,s,l,u,c,d,f,p,h,m,g,v,y,b,E,T,w;for(E=[],n=0;n=0&&!(E[y].level<=l);y--);if(E.length=y+1,"text"===r.type){a=0,s=(i=r.content).length;e:for(;a=0)c=i.charCodeAt(o.index-1);else for(y=n-1;y>=0&&"softbreak"!==e[y].type&&"hardbreak"!==e[y].type;y--)if(e[y].content){c=e[y].content.charCodeAt(e[y].content.length-1);break}if(d=32,a=48&&c<=57&&(v=g=!1),g&&v&&(g=f,v=p),g||v){if(v)for(y=E.length-1;y>=0&&(u=E[y],!(E[y].level=0;t--)"inline"===e.tokens[t].type&&ig.test(e.tokens[t].content)&&lg(e.tokens[t].children,e)}),"smartquotes");function cg(e,t,n){this.type=e,this.tag=t,this.attrs=null,this.map=null,this.nesting=n,this.level=0,this.children=null,this.content="",this.markup="",this.info="",this.meta=null,this.block=!1,this.hidden=!1}g(cg,"Token$3"),cg.prototype.attrIndex=g((function(e){var t,n,r;if(!this.attrs)return-1;for(n=0,r=(t=this.attrs).length;n=0&&(n=this.attrs[t][1]),n}),"attrGet"),cg.prototype.attrJoin=g((function(e,t){var n=this.attrIndex(e);n<0?this.attrPush([e,t]):this.attrs[n][1]=this.attrs[n][1]+" "+t}),"attrJoin");var dg=cg,fg=dg;function pg(e,t,n){this.src=e,this.env=n,this.tokens=[],this.inlineMode=!1,this.md=t}g(pg,"StateCore"),pg.prototype.Token=fg;var hg=pg,mg=Pm,gg=[["normalize",Um],["block",Bm],["inline",$m],["linkify",zm],["replacements",eg],["smartquotes",ug]];function vg(){this.ruler=new mg;for(var e=0;en)return!1;if(u=t+1,e.sCount[u]=4)return!1;if((a=e.bMarks[u]+e.tShift[u])>=e.eMarks[u])return!1;if(124!==(E=e.src.charCodeAt(a++))&&45!==E&&58!==E)return!1;if(a>=e.eMarks[u])return!1;if(124!==(T=e.src.charCodeAt(a++))&&45!==T&&58!==T&&!bg(T))return!1;if(45===E&&bg(T))return!1;for(;a=4)return!1;if((c=Tg(o)).length&&""===c[0]&&c.shift(),c.length&&""===c[c.length-1]&&c.pop(),0===(d=c.length)||d!==p.length)return!1;if(r)return!0;for(v=e.parentType,e.parentType="table",b=e.md.block.ruler.getRules("blockquote"),(f=e.push("table_open","table",1)).map=m=[t,0],(f=e.push("thead_open","thead",1)).map=[t,t+1],(f=e.push("tr_open","tr",1)).map=[t,t+1],s=0;s=4)break;for((c=Tg(o)).length&&""===c[0]&&c.shift(),c.length&&""===c[c.length-1]&&c.pop(),u===t+2&&((f=e.push("tbody_open","tbody",1)).map=g=[t+2,0]),(f=e.push("tr_open","tr",1)).map=[u,u+1],s=0;s=4))break;i=++r}return e.line=i,(o=e.push("code_block","code",0)).content=e.getLines(t,i,4+e.blkIndent,!1)+"\n",o.map=[t,e.line],!0}),"code"),Sg=g((function(e,t,n,r){var i,o,a,s,l,u,c,d=!1,f=e.bMarks[t]+e.tShift[t],p=e.eMarks[t];if(e.sCount[t]-e.blkIndent>=4)return!1;if(f+3>p)return!1;if(126!==(i=e.src.charCodeAt(f))&&96!==i)return!1;if(l=f,(o=(f=e.skipChars(f,i))-l)<3)return!1;if(c=e.src.slice(l,f),a=e.src.slice(f,p),96===i&&a.indexOf(String.fromCharCode(i))>=0)return!1;if(r)return!0;for(s=t;!(++s>=n||(f=l=e.bMarks[s]+e.tShift[s])<(p=e.eMarks[s])&&e.sCount[s]=4||(f=e.skipChars(f,i))-l=4)return!1;if(62!==e.src.charCodeAt(x++))return!1;if(r)return!0;for(s=f=e.sCount[t]+1,32===e.src.charCodeAt(x)?(x++,s++,f++,i=!1,b=!0):9===e.src.charCodeAt(x)?(b=!0,(e.bsCount[t]+f)%4==3?(x++,s++,f++,i=!1):i=!0):b=!1,p=[e.bMarks[t]],e.bMarks[t]=x;x=k,v=[e.sCount[t]],e.sCount[t]=f-s,y=[e.tShift[t]],e.tShift[t]=x-e.bMarks[t],T=e.md.block.ruler.getRules("blockquote"),g=e.parentType,e.parentType="blockquote",d=t+1;d=(k=e.eMarks[d])));d++)if(62!==e.src.charCodeAt(x++)||C){if(u)break;for(E=!1,a=0,l=T.length;a=k,h.push(e.bsCount[d]),e.bsCount[d]=e.sCount[d]+1+(b?1:0),v.push(e.sCount[d]),e.sCount[d]=f-s,y.push(e.tShift[d]),e.tShift[d]=x-e.bMarks[d]}for(m=e.blkIndent,e.blkIndent=0,(w=e.push("blockquote_open","blockquote",1)).markup=">",w.map=c=[t,0],e.md.block.tokenize(e,t,d),(w=e.push("blockquote_close","blockquote",-1)).markup=">",e.lineMax=S,e.parentType=g,c[1]=e.line,a=0;a=4)return!1;if(42!==(i=e.src.charCodeAt(l++))&&45!==i&&95!==i)return!1;for(o=1;l=o)return-1;if((n=e.src.charCodeAt(i++))<48||n>57)return-1;for(;;){if(i>=o)return-1;if(!((n=e.src.charCodeAt(i++))>=48&&n<=57)){if(41===n||46===n)break;return-1}if(i-r>=10)return-1}return i=4)return!1;if(e.listIndent>=0&&e.sCount[t]-e.listIndent>=4&&e.sCount[t]=e.blkIndent&&(L=!0),(k=Dg(e,t))>=0){if(c=!0,_=e.bMarks[t]+e.tShift[t],g=Number(e.src.slice(_,k-1)),L&&1!==g)return!1}else{if(!((k=Ig(e,t))>=0))return!1;c=!1}if(L&&e.skipSpaces(k)>=e.eMarks[t])return!1;if(m=e.src.charCodeAt(k-1),r)return!0;for(h=e.tokens.length,c?(D=e.push("ordered_list_open","ol",1),1!==g&&(D.attrs=[["start",g]])):D=e.push("bullet_list_open","ul",1),D.map=p=[t,0],D.markup=String.fromCharCode(m),y=t,N=!1,I=e.md.block.ruler.getRules("list"),T=e.parentType,e.parentType="list";y=v?1:b-u)>4&&(l=1),s=u+l,(D=e.push("list_item_open","li",1)).markup=String.fromCharCode(m),D.map=d=[t,0],c&&(D.info=e.src.slice(_,k-1)),S=e.tight,C=e.tShift[t],w=e.sCount[t],E=e.listIndent,e.listIndent=e.blkIndent,e.blkIndent=s,e.tight=!0,e.tShift[t]=o-e.bMarks[t],e.sCount[t]=b,o>=v&&e.isEmpty(t+1)?e.line=Math.min(e.line+2,n):e.md.block.tokenize(e,t,n,!0),e.tight&&!N||(A=!1),N=e.line-t>1&&e.isEmpty(e.line-1),e.blkIndent=e.listIndent,e.listIndent=E,e.tShift[t]=C,e.sCount[t]=w,e.tight=S,(D=e.push("list_item_close","li",-1)).markup=String.fromCharCode(m),y=t=e.line,d[1]=y,o=e.bMarks[t],y>=n)break;if(e.sCount[y]=4)break;for(O=!1,a=0,f=I.length;a=4)return!1;if(91!==e.src.charCodeAt(T))return!1;for(;++T3||e.sCount[C]<0)){for(v=!1,u=0,c=y.length;u`\\x00-\\x20]+|'[^']*'|\"[^\"]*\"))?)*\\s*\\/?>",Vg="<\\/[A-Za-z][A-Za-z0-9\\-]*\\s*>",Ug=new RegExp("^(?:"+jg+"|"+Vg+"|\x3c!----\x3e|\x3c!--(?:-?[^>-])(?:-?[^-])*--\x3e|<[?][\\s\\S]*?[?]>|]*>|)"),Bg=new RegExp("^(?:"+jg+"|"+Vg+")");Pg.HTML_TAG_RE=Ug,Pg.HTML_OPEN_CLOSE_TAG_RE=Bg;var $g=["address","article","aside","base","basefont","blockquote","body","caption","center","col","colgroup","dd","details","dialog","dir","div","dl","dt","fieldset","figcaption","figure","footer","form","frame","frameset","h1","h2","h3","h4","h5","h6","head","header","hr","html","iframe","legend","li","link","main","menu","menuitem","nav","noframes","ol","optgroup","option","p","param","section","source","summary","table","tbody","td","tfoot","th","thead","title","tr","track","ul"],qg=Pg.HTML_OPEN_CLOSE_TAG_RE,Hg=[[/^<(script|pre|style|textarea)(?=(\s|>|$))/i,/<\/(script|pre|style|textarea)>/i,!0],[/^/,!0],[/^<\?/,/\?>/,!0],[/^/,!0],[/^/,!0],[new RegExp("^|$))","i"),/^$/,!0],[new RegExp(qg.source+"\\s*$"),/^$/,!1]],Gg=g((function(e,t,n,r){var i,o,a,s,l=e.bMarks[t]+e.tShift[t],u=e.eMarks[t];if(e.sCount[t]-e.blkIndent>=4)return!1;if(!e.md.options.html)return!1;if(60!==e.src.charCodeAt(l))return!1;for(s=e.src.slice(l,u),i=0;i=4)return!1;if(35!==(i=e.src.charCodeAt(l))||l>=u)return!1;for(o=1,i=e.src.charCodeAt(++l);35===i&&l6||ll&&zg(e.src.charCodeAt(a-1))&&(u=a),e.line=t+1,(s=e.push("heading_open","h"+String(o),1)).markup="########".slice(0,o),s.map=[t,e.line],(s=e.push("inline","",0)).content=e.src.slice(l,u).trim(),s.map=[t,e.line],s.children=[],(s=e.push("heading_close","h"+String(o),-1)).markup="########".slice(0,o)),0))}),"heading"),Kg=g((function(e,t,n){var r,i,o,a,s,l,u,c,d,f,p=t+1,h=e.md.block.ruler.getRules("paragraph");if(e.sCount[t]-e.blkIndent>=4)return!1;for(f=e.parentType,e.parentType="paragraph";p3)){if(e.sCount[p]>=e.blkIndent&&(l=e.bMarks[p]+e.tShift[p])<(u=e.eMarks[p])&&(45===(d=e.src.charCodeAt(l))||61===d)&&(l=e.skipChars(l,d),(l=e.skipSpaces(l))>=u)){c=61===d?1:2;break}if(!(e.sCount[p]<0)){for(i=!1,o=0,a=h.length;o3||e.sCount[l]<0)){for(r=!1,i=0,o=u.length;i0&&this.level++,this.tokens.push(r),r},Jg.prototype.isEmpty=g((function(e){return this.bMarks[e]+this.tShift[e]>=this.eMarks[e]}),"isEmpty"),Jg.prototype.skipEmptyLines=g((function(e){for(var t=this.lineMax;et;)if(!Yg(this.src.charCodeAt(--e)))return e+1;return e}),"skipSpacesBack"),Jg.prototype.skipChars=g((function(e,t){for(var n=this.src.length;en;)if(t!==this.src.charCodeAt(--e))return e+1;return e}),"skipCharsBack"),Jg.prototype.getLines=g((function(e,t,n,r){var i,o,a,s,l,u,c,d=e;if(e>=t)return"";for(u=new Array(t-e),i=0;dn?new Array(o-n+1).join(" ")+this.src.slice(s,l):this.src.slice(s,l)}return u.join("")}),"getLines"),Jg.prototype.Token=Xg;var Zg=Jg,ev=Pm,tv=[["table",wg,["paragraph","reference"]],["code",Cg],["fence",Sg,["paragraph","reference","blockquote","list"]],["blockquote",kg,["paragraph","reference","blockquote","list"]],["hr",_g,["paragraph","reference","blockquote","list"]],["list",Ag,["paragraph","reference","blockquote"]],["reference",Fg],["html_block",Gg,["paragraph","reference","blockquote"]],["heading",Wg,["paragraph","reference","blockquote"]],["lheading",Kg],["paragraph",Qg]];function nv(){this.ruler=new ev;for(var e=0;e=n))&&!(e.sCount[a]=l){e.line=n;break}for(r=0;r=0&&32===e.pending.charCodeAt(n)?n>=1&&32===e.pending.charCodeAt(n-1)?(e.pending=e.pending.replace(/ +$/,""),e.push("hardbreak","br",0)):(e.pending=e.pending.slice(0,-1),e.push("softbreak","br",0)):e.push("softbreak","br",0)),i++;i?@[]^_`{|}~-".split("").forEach((function(e){uv[e.charCodeAt(0)]=1}));var dv=g((function(e,t){var n,r=e.pos,i=e.posMax;if(92!==e.src.charCodeAt(r))return!1;if(++r=0;n--)95!==(r=t[n]).marker&&42!==r.marker||-1!==r.end&&(i=t[r.end],s=n>0&&t[n-1].end===r.end+1&&t[n-1].token===r.token-1&&t[r.end+1].token===i.token+1&&t[n-1].marker===r.marker,a=String.fromCharCode(r.marker),(o=e.tokens[r.token]).type=s?"strong_open":"em_open",o.tag=s?"strong":"em",o.nesting=1,o.markup=s?a+a:a,o.content="",(o=e.tokens[i.token]).type=s?"strong_close":"em_close",o.tag=s?"strong":"em",o.nesting=-1,o.markup=s?a+a:a,o.content="",s&&(e.tokens[t[n-1].token].content="",e.tokens[t[r.end+1].token].content="",n--))}mv.tokenize=g((function(e,t){var n,r,i=e.pos,o=e.src.charCodeAt(i);if(t)return!1;if(95!==o&&42!==o)return!1;for(r=e.scanDelims(e.pos,42===o),n=0;n=p)return!1;if(h=s,(l=e.md.helpers.parseLinkDestination(e.src,s,e.posMax)).ok){for(c=e.md.normalizeLink(l.str),e.md.validateLink(c)?s=l.pos:c="",h=s;s=p||41!==e.src.charCodeAt(s))&&(m=!0),s++}if(m){if(void 0===e.env.references)return!1;if(s=0?i=e.src.slice(h,s++):s=o+1):s=o+1,i||(i=e.src.slice(a,o)),!(u=e.env.references[vv(i)]))return e.pos=f,!1;c=u.href,d=u.title}return t||(e.pos=a,e.posMax=o,e.push("link_open","a",1).attrs=n=[["href",c]],d&&n.push(["title",d]),e.md.inline.tokenize(e),e.push("link_close","a",-1)),e.pos=s,e.posMax=p,!0}),"link"),Ev=Wh.normalizeReference,Tv=Wh.isSpace,wv=g((function(e,t){var n,r,i,o,a,s,l,u,c,d,f,p,h,m="",g=e.pos,v=e.posMax;if(33!==e.src.charCodeAt(e.pos))return!1;if(91!==e.src.charCodeAt(e.pos+1))return!1;if(s=e.pos+2,(a=e.md.helpers.parseLinkLabel(e,e.pos+1,!1))<0)return!1;if((l=a+1)=v)return!1;for(h=l,(c=e.md.helpers.parseLinkDestination(e.src,l,e.posMax)).ok&&(m=e.md.normalizeLink(c.str),e.md.validateLink(m)?l=c.pos:m=""),h=l;l=v||41!==e.src.charCodeAt(l))return e.pos=g,!1;l++}else{if(void 0===e.env.references)return!1;if(l=0?o=e.src.slice(h,l++):l=a+1):l=a+1,o||(o=e.src.slice(s,a)),!(u=e.env.references[Ev(o)]))return e.pos=g,!1;m=u.href,d=u.title}return t||(i=e.src.slice(s,a),e.md.inline.parse(i,e.md,e.env,p=[]),(f=e.push("image","img",0)).attrs=n=[["src",m],["alt",""]],f.children=p,f.content=i,d&&n.push(["title",d])),e.pos=l,e.posMax=v,!0}),"image"),Cv=/^([a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)$/,Sv=/^([a-zA-Z][a-zA-Z0-9+.\-]{1,31}):([^<>\x00-\x20]*)$/,xv=g((function(e,t){var n,r,i,o,a,s,l=e.pos;if(60!==e.src.charCodeAt(l))return!1;for(a=e.pos,s=e.posMax;;){if(++l>=s)return!1;if(60===(o=e.src.charCodeAt(l)))return!1;if(62===o)break}return n=e.src.slice(a+1,l),Sv.test(n)?(r=e.md.normalizeLink(n),!!e.md.validateLink(r)&&(t||((i=e.push("link_open","a",1)).attrs=[["href",r]],i.markup="autolink",i.info="auto",(i=e.push("text","",0)).content=e.md.normalizeLinkText(n),(i=e.push("link_close","a",-1)).markup="autolink",i.info="auto"),e.pos+=n.length+2,!0)):!!Cv.test(n)&&(r=e.md.normalizeLink("mailto:"+n),!!e.md.validateLink(r)&&(t||((i=e.push("link_open","a",1)).attrs=[["href",r]],i.markup="autolink",i.info="auto",(i=e.push("text","",0)).content=e.md.normalizeLinkText(n),(i=e.push("link_close","a",-1)).markup="autolink",i.info="auto"),e.pos+=n.length+2,!0))}),"autolink"),kv=Pg.HTML_TAG_RE;function Nv(e){var t=32|e;return t>=97&&t<=122}g(Nv,"isLetter");var _v=g((function(e,t){var n,r,i,o=e.pos;return!(!e.md.options.html||(i=e.posMax,60!==e.src.charCodeAt(o)||o+2>=i||33!==(n=e.src.charCodeAt(o+1))&&63!==n&&47!==n&&!Nv(n)||!(r=e.src.slice(o).match(kv))||(t||(e.push("html_inline","",0).content=e.src.slice(o,o+r[0].length)),e.pos+=r[0].length,0)))}),"html_inline"),Ov=Kh,Iv=Wh.has,Dv=Wh.isValidEntityCode,Lv=Wh.fromCodePoint,Av=/^&#((?:x[a-f0-9]{1,6}|[0-9]{1,7}));/i,Mv=/^&([a-z][a-z0-9]{1,31});/i,Rv=g((function(e,t){var n,r,i=e.pos,o=e.posMax;if(38!==e.src.charCodeAt(i))return!1;if(i+1a;r-=o.jump+1)if((o=t[r]).marker===i.marker&&o.open&&o.end<0&&(l=!1,(o.close||i.open)&&(o.length+i.length)%3==0&&(o.length%3==0&&i.length%3==0||(l=!0)),!l)){u=r>0&&!t[r-1].open?t[r-1].jump+1:0,i.jump=n-r+u,i.open=!1,o.end=n,o.jump=u,o.close=!1,s=-1;break}-1!==s&&(c[i.marker][(i.open?3:0)+(i.length||0)%3]=s)}}g(Fv,"processDelimiters");var Pv=g((function(e){var t,n=e.tokens_meta,r=e.tokens_meta.length;for(Fv(0,e.delimiters),t=0;t0&&r++,"text"===i[t].type&&t+10&&(this.level++,this._prev_delimiters.push(this.delimiters),this.delimiters=[],i={delimiters:this.delimiters}),this.pendingLevel=this.level,this.tokens.push(r),this.tokens_meta.push(i),r},qv.prototype.scanDelims=function(e,t){var n,r,i,o,a,s,l,u,c,d=e,f=!0,p=!0,h=this.posMax,m=this.src.charCodeAt(e);for(n=e>0?this.src.charCodeAt(e-1):32;d=o)break}else e.pending+=e.src[e.pos++]}e.pending&&e.pushPending()},Kv.prototype.parse=function(e,t,n,r){var i,o,a,s=new this.State(e,t,n,r);for(this.tokenize(s),a=(o=this.ruler2.getRules("")).length,i=0;i|$))",t.tpl_email_fuzzy='(^|[><|]|"|\\(|'+t.src_ZCc+")("+t.src_email_name+"@"+t.tpl_host_fuzzy_strict+")",t.tpl_link_fuzzy="(^|(?![.:/\\-_@])(?:[$+<=>^`||]|"+t.src_ZPCc+"))((?![$+<=>^`||])"+t.tpl_host_port_fuzzy_strict+t.src_path+")",t.tpl_link_no_ip_fuzzy="(^|(?![.:/\\-_@])(?:[$+<=>^`||]|"+t.src_ZPCc+"))((?![$+<=>^`||])"+t.tpl_host_port_no_ip_fuzzy_strict+t.src_path+")",t}),"re");function Yv(e){return Array.prototype.slice.call(arguments,1).forEach((function(t){t&&Object.keys(t).forEach((function(n){e[n]=t[n]}))})),e}function Jv(e){return Object.prototype.toString.call(e)}function Zv(e){return"[object String]"===Jv(e)}function ey(e){return"[object Object]"===Jv(e)}function ty(e){return"[object RegExp]"===Jv(e)}function ny(e){return"[object Function]"===Jv(e)}function ry(e){return e.replace(/[.?*+^$[\]\\(){}|-]/g,"\\$&")}g(Yv,"assign"),g(Jv,"_class"),g(Zv,"isString"),g(ey,"isObject"),g(ty,"isRegExp"),g(ny,"isFunction"),g(ry,"escapeRE");var iy={fuzzyLink:!0,fuzzyEmail:!0,fuzzyIP:!1};function oy(e){return Object.keys(e||{}).reduce((function(e,t){return e||iy.hasOwnProperty(t)}),!1)}g(oy,"isOptionsObj");var ay={"http:":{validate:function(e,t,n){var r=e.slice(t);return n.re.http||(n.re.http=new RegExp("^\\/\\/"+n.re.src_auth+n.re.src_host_port_strict+n.re.src_path,"i")),n.re.http.test(r)?r.match(n.re.http)[0].length:0}},"https:":"http:","ftp:":"http:","//":{validate:function(e,t,n){var r=e.slice(t);return n.re.no_http||(n.re.no_http=new RegExp("^"+n.re.src_auth+"(?:localhost|(?:(?:"+n.re.src_domain+")\\.)+"+n.re.src_domain_root+")"+n.re.src_port+n.re.src_host_terminator+n.re.src_path,"i")),n.re.no_http.test(r)?t>=3&&":"===e[t-3]||t>=3&&"/"===e[t-3]?0:r.match(n.re.no_http)[0].length:0}},"mailto:":{validate:function(e,t,n){var r=e.slice(t);return n.re.mailto||(n.re.mailto=new RegExp("^"+n.re.src_email_name+"@"+n.re.src_host_strict,"i")),n.re.mailto.test(r)?r.match(n.re.mailto)[0].length:0}}},sy="a[cdefgilmnoqrstuwxz]|b[abdefghijmnorstvwyz]|c[acdfghiklmnoruvwxyz]|d[ejkmoz]|e[cegrstu]|f[ijkmor]|g[abdefghilmnpqrstuwy]|h[kmnrtu]|i[delmnoqrst]|j[emop]|k[eghimnprwyz]|l[abcikrstuvy]|m[acdeghklmnopqrstuvwxyz]|n[acefgilopruz]|om|p[aefghklmnrstwy]|qa|r[eosuw]|s[abcdeghijklmnortuvxyz]|t[cdfghjklmnortvwz]|u[agksyz]|v[aceginu]|w[fs]|y[et]|z[amw]",ly="biz|com|edu|gov|net|org|pro|web|xxx|aero|asia|coop|info|museum|name|shop|рф".split("|");function uy(e){e.__index__=-1,e.__text_cache__=""}function cy(e){return function(t,n){var r=t.slice(n);return e.test(r)?r.match(e)[0].length:0}}function dy(){return function(e,t){t.normalize(e)}}function fy(e){var t=e.re=Xv(e.__opts__),n=e.__tlds__.slice();function r(e){return e.replace("%TLDS%",t.src_tlds)}e.onCompile(),e.__tlds_replaced__||n.push(sy),n.push(t.src_xn),t.src_tlds=n.join("|"),g(r,"untpl"),t.email_fuzzy=RegExp(r(t.tpl_email_fuzzy),"i"),t.link_fuzzy=RegExp(r(t.tpl_link_fuzzy),"i"),t.link_no_ip_fuzzy=RegExp(r(t.tpl_link_no_ip_fuzzy),"i"),t.host_fuzzy_test=RegExp(r(t.tpl_host_fuzzy_test),"i");var i=[];function o(e,t){throw new Error('(LinkifyIt) Invalid schema "'+e+'": '+t)}e.__compiled__={},g(o,"schemaError"),Object.keys(e.__schemas__).forEach((function(t){var n=e.__schemas__[t];if(null!==n){var r={validate:null,link:null};if(e.__compiled__[t]=r,ey(n))return ty(n.validate)?r.validate=cy(n.validate):ny(n.validate)?r.validate=n.validate:o(t,n),void(ny(n.normalize)?r.normalize=n.normalize:n.normalize?o(t,n):r.normalize=function(e,t){t.normalize(e)});Zv(n)?i.push(t):o(t,n)}})),i.forEach((function(t){e.__compiled__[e.__schemas__[t]]&&(e.__compiled__[t].validate=e.__compiled__[e.__schemas__[t]].validate,e.__compiled__[t].normalize=e.__compiled__[e.__schemas__[t]].normalize)})),e.__compiled__[""]={validate:null,normalize:function(e,t){t.normalize(e)}};var a=Object.keys(e.__compiled__).filter((function(t){return t.length>0&&e.__compiled__[t]})).map(ry).join("|");e.re.schema_test=RegExp("(^|(?!_)(?:[><|]|"+t.src_ZPCc+"))("+a+")","i"),e.re.schema_search=RegExp("(^|(?!_)(?:[><|]|"+t.src_ZPCc+"))("+a+")","ig"),e.re.pretest=RegExp("("+e.re.schema_test.source+")|("+e.re.host_fuzzy_test.source+")|@","i"),uy(e)}function py(e,t){var n=e.__index__,r=e.__last_index__,i=e.__text_cache__.slice(n,r);this.schema=e.__schema__.toLowerCase(),this.index=n+t,this.lastIndex=r+t,this.raw=i,this.text=i,this.url=i}function hy(e,t){var n=new py(e,t);return e.__compiled__[n.schema].normalize(n,e),n}function my(e,t){if(!(this instanceof my))return new my(e,t);t||oy(e)&&(t=e,e={}),this.__opts__=Yv({},iy,t),this.__index__=-1,this.__last_index__=-1,this.__schema__="",this.__text_cache__="",this.__schemas__=Yv({},ay,e),this.__compiled__={},this.__tlds__=ly,this.__tlds_replaced__=!1,this.re={},fy(this)}g(uy,"resetScanCache"),g(cy,"createValidator"),g(dy,"createNormalizer"),g(fy,"compile"),g(py,"Match"),g(hy,"createMatch"),g(my,"LinkifyIt$1"),my.prototype.add=g((function(e,t){return this.__schemas__[e]=t,fy(this),this}),"add"),my.prototype.set=g((function(e){return this.__opts__=Yv(this.__opts__,e),this}),"set"),my.prototype.test=g((function(e){if(this.__text_cache__=e,this.__index__=-1,!e.length)return!1;var t,n,r,i,o,a,s,l;if(this.re.schema_test.test(e))for((s=this.re.schema_search).lastIndex=0;null!==(t=s.exec(e));)if(i=this.testSchemaAt(e,t[2],s.lastIndex)){this.__schema__=t[2],this.__index__=t.index+t[1].length,this.__last_index__=t.index+t[0].length+i;break}return this.__opts__.fuzzyLink&&this.__compiled__["http:"]&&(l=e.search(this.re.host_fuzzy_test))>=0&&(this.__index__<0||l=0&&null!==(r=e.match(this.re.email_fuzzy))&&(o=r.index+r[1].length,a=r.index+r[0].length,(this.__index__<0||othis.__last_index__)&&(this.__schema__="mailto:",this.__index__=o,this.__last_index__=a)),this.__index__>=0}),"test"),my.prototype.pretest=g((function(e){return this.re.pretest.test(e)}),"pretest"),my.prototype.testSchemaAt=g((function(e,t,n){return this.__compiled__[t.toLowerCase()]?this.__compiled__[t.toLowerCase()].validate(e,n,this):0}),"testSchemaAt"),my.prototype.match=g((function(e){var t=0,n=[];this.__index__>=0&&this.__text_cache__===e&&(n.push(hy(this,t)),t=this.__last_index__);for(var r=t?e.slice(t):e;this.test(r);)n.push(hy(this,t)),r=r.slice(this.__last_index__),t+=this.__last_index__;return n.length?n:null}),"match"),my.prototype.tlds=g((function(e,t){return e=Array.isArray(e)?e:[e],t?(this.__tlds__=this.__tlds__.concat(e).sort().filter((function(e,t,n){return e!==n[t-1]})).reverse(),fy(this),this):(this.__tlds__=e.slice(),this.__tlds_replaced__=!0,fy(this),this)}),"tlds"),my.prototype.normalize=g((function(e){e.schema||(e.url="http://"+e.url),"mailto:"!==e.schema||/^mailto:/i.test(e.url)||(e.url="mailto:"+e.url)}),"normalize"),my.prototype.onCompile=g((function(){}),"onCompile");var gy=my;const vy=2147483647,yy=36,by=/^xn--/,Ey=/[^\0-\x7E]/,Ty=/[\x2E\u3002\uFF0E\uFF61]/g,wy={overflow:"Overflow: input needs wider integers to process","not-basic":"Illegal input >= 0x80 (not a basic code point)","invalid-input":"Invalid input"},Cy=Math.floor,Sy=String.fromCharCode;function xy(e){throw new RangeError(wy[e])}function ky(e,t){const n=[];let r=e.length;for(;r--;)n[r]=t(e[r]);return n}function Ny(e,t){const n=e.split("@");let r="";return n.length>1&&(r=n[0]+"@",e=n[1]),r+ky((e=e.replace(Ty,".")).split("."),t).join(".")}function _y(e){const t=[];let n=0;const r=e.length;for(;n=55296&&i<=56319&&nString.fromCodePoint(...e)),"ucs2encode"),Iy=g((function(e){return e-48<10?e-22:e-65<26?e-65:e-97<26?e-97:yy}),"basicToDigit"),Dy=g((function(e,t){return e+22+75*(e<26)-((0!=t)<<5)}),"digitToBasic"),Ly=g((function(e,t,n){let r=0;for(e=n?Cy(e/700):e>>1,e+=Cy(e/t);e>455;r+=yy)e=Cy(e/35);return Cy(r+36*e/(e+38))}),"adapt"),Ay=g((function(e){const t=[],n=e.length;let r=0,i=128,o=72,a=e.lastIndexOf("-");a<0&&(a=0);for(let n=0;n=128&&xy("not-basic"),t.push(e.charCodeAt(n));for(let s=a>0?a+1:0;s=n&&xy("invalid-input");const a=Iy(e.charCodeAt(s++));(a>=yy||a>Cy((vy-r)/t))&&xy("overflow"),r+=a*t;const l=i<=o?1:i>=o+26?26:i-o;if(aCy(vy/u)&&xy("overflow"),t*=u}const l=t.length+1;o=Ly(r-a,l,0==a),Cy(r/l)>vy-i&&xy("overflow"),i+=Cy(r/l),r%=l,t.splice(r++,0,i)}return String.fromCodePoint(...t)}),"decode"),My=g((function(e){const t=[];let n=(e=_y(e)).length,r=128,i=0,o=72;for(const n of e)n<128&&t.push(Sy(n));let a=t.length,s=a;for(a&&t.push("-");s=r&&tCy((vy-i)/l)&&xy("overflow"),i+=(n-r)*l,r=n;for(const n of e)if(nvy&&xy("overflow"),n==r){let e=i;for(let n=yy;;n+=yy){const r=n<=o?1:n>=o+26?26:n-o;if(e=0))try{t.hostname=Wy.toASCII(t.hostname)}catch(e){}return zy.encode(zy.format(t))}function eb(e){var t=zy.parse(e,!0);if(t.hostname&&(!t.protocol||Jy.indexOf(t.protocol)>=0))try{t.hostname=Wy.toUnicode(t.hostname)}catch(e){}return zy.decode(zy.format(t),zy.decode.defaultChars+"%")}function tb(e,t){if(!(this instanceof tb))return new tb(e,t);t||Vy.isString(e)||(t=e||{},e="default"),this.inline=new Hy,this.block=new qy,this.core=new $y,this.renderer=new By,this.linkify=new Gy,this.validateLink=Yy,this.normalizeLink=Zy,this.normalizeLinkText=eb,this.utils=Vy,this.helpers=Vy.assign({},Uy),this.options={},this.configure(e),t&&this.set(t)}g(Zy,"normalizeLink"),g(eb,"normalizeLinkText"),g(tb,"MarkdownIt"),tb.prototype.set=function(e){return Vy.assign(this.options,e),this},tb.prototype.configure=function(e){var t,n=this;if(Vy.isString(e)&&!(e=Ky[t=e]))throw new Error('Wrong `markdown-it` preset "'+t+'", check name');if(!e)throw new Error("Wrong `markdown-it` preset, can't be empty");return e.options&&n.set(e.options),e.components&&Object.keys(e.components).forEach((function(t){e.components[t].rules&&n[t].ruler.enableOnly(e.components[t].rules),e.components[t].rules2&&n[t].ruler2.enableOnly(e.components[t].rules2)})),this},tb.prototype.enable=function(e,t){var n=[];Array.isArray(e)||(e=[e]),["core","block","inline"].forEach((function(t){n=n.concat(this[t].ruler.enable(e,!0))}),this),n=n.concat(this.inline.ruler2.enable(e,!0));var r=e.filter((function(e){return n.indexOf(e)<0}));if(r.length&&!t)throw new Error("MarkdownIt. Failed to enable unknown rule(s): "+r);return this},tb.prototype.disable=function(e,t){var n=[];Array.isArray(e)||(e=[e]),["core","block","inline"].forEach((function(t){n=n.concat(this[t].ruler.disable(e,!0))}),this),n=n.concat(this.inline.ruler2.disable(e,!0));var r=e.filter((function(e){return n.indexOf(e)<0}));if(r.length&&!t)throw new Error("MarkdownIt. Failed to disable unknown rule(s): "+r);return this},tb.prototype.use=function(e){var t=[this].concat(Array.prototype.slice.call(arguments,1));return e.apply(e,t),this},tb.prototype.parse=function(e,t){if("string"!=typeof e)throw new Error("Input data should be a String");var n=new this.core.State(e,this,t);return this.core.process(n),n.tokens},tb.prototype.render=function(e,t){return t=t||{},this.renderer.render(this.parse(e,t),this.options,t)},tb.prototype.parseInline=function(e,t){var n=new this.core.State(e,this,t);return n.inlineMode=!0,this.core.process(n),n.tokens},tb.prototype.renderInline=function(e,t){return t=t||{},this.renderer.render(this.parseInline(e,t),this.options,t)};const nb=new tb({breaks:!0,linkify:!0}),rb=(0,t.forwardRef)(((e,t)=>{var n=e,{children:r,onlyShowFirstChild:i,type:o}=n,a=v(n,["children","onlyShowFirstChild","type"]);return de("div",m(h({},a),{ref:t,className:b(`graphiql-markdown-${o}`,i&&"graphiql-markdown-preview",a.className),dangerouslySetInnerHTML:{__html:nb.render(r)}}))}));e.aM=rb,rb.displayName="MarkdownContent";const ib=(0,t.forwardRef)(((e,t)=>de("div",m(h({},e),{ref:t,className:b("graphiql-spinner",e.className)}))));function ob(e){var t,n,r=ms(e),i=r.defaultView||window;return r?{width:null!=(t=r.documentElement.clientWidth)?t:i.innerWidth,height:null!=(n=r.documentElement.clientHeight)?n:i.innerHeight}:{width:0,height:0}}function ab(){return ab=Object.assign||function(e){for(var t=1;t=0||(i[n]=e[n]);return i}e.aN=ib,ib.displayName="Spinner",g(ob,"getDocumentDimensions"),g(ab,"_extends$1"),g(sb,"_objectWithoutPropertiesLoose$1");var lb,ub,cb,db,fb,pb,hb,mb,gb,vb,yb=["children","label","ariaLabel","id","DEBUG_STYLE"],bb=["label","ariaLabel","isVisible","id"],Eb=["ariaLabel","aria-label","as","id","isVisible","label","position","style","triggerRect"],Tb=["type"],wb=100,Cb=500;(vb=hb||(hb={})).Idle="IDLE",vb.Focused="FOCUSED",vb.Visible="VISIBLE",vb.LeavingVisible="LEAVING_VISIBLE",vb.Dismissed="DISMISSED",(gb=mb||(mb={})).Blur="BLUR",gb.Focus="FOCUS",gb.GlobalMouseMove="GLOBAL_MOUSE_MOVE",gb.MouseDown="MOUSE_DOWN",gb.MouseEnter="MOUSE_ENTER",gb.MouseLeave="MOUSE_LEAVE",gb.MouseMove="MOUSE_MOVE",gb.Rest="REST",gb.SelectWithKeyboard="SELECT_WITH_KEYBOARD",gb.TimeComplete="TIME_COMPLETE";var Sb,xb,kb={initial:hb.Idle,states:(pb={},pb[hb.Idle]={enter:Rb,on:(lb={},lb[mb.MouseEnter]=hb.Focused,lb[mb.Focus]=hb.Visible,lb)},pb[hb.Focused]={enter:Db,leave:Lb,on:(ub={},ub[mb.MouseMove]=hb.Focused,ub[mb.MouseLeave]=hb.Idle,ub[mb.MouseDown]=hb.Dismissed,ub[mb.Blur]=hb.Idle,ub[mb.Rest]=hb.Visible,ub)},pb[hb.Visible]={on:(cb={},cb[mb.Focus]=hb.Focused,cb[mb.MouseEnter]=hb.Focused,cb[mb.MouseLeave]=hb.LeavingVisible,cb[mb.Blur]=hb.LeavingVisible,cb[mb.MouseDown]=hb.Dismissed,cb[mb.SelectWithKeyboard]=hb.Dismissed,cb[mb.GlobalMouseMove]=hb.LeavingVisible,cb)},pb[hb.LeavingVisible]={enter:Ab,leave:g((function(){Mb(),Rb()}),"leave"),on:(db={},db[mb.MouseEnter]=hb.Visible,db[mb.Focus]=hb.Visible,db[mb.TimeComplete]=hb.Idle,db)},pb[hb.Dismissed]={leave:g((function(){Rb()}),"leave"),on:(fb={},fb[mb.MouseLeave]=hb.Idle,fb[mb.Blur]=hb.Idle,fb)},pb)},Nb={value:kb.initial,context:{id:null}},_b=[];function Ob(e){return _b.push(e),function(){_b.splice(_b.indexOf(e),1)}}function Ib(){_b.forEach((function(e){return e(Nb)}))}function Db(){window.clearTimeout(Sb),Sb=window.setTimeout((function(){qb({type:mb.Rest})}),wb)}function Lb(){window.clearTimeout(Sb)}function Ab(){window.clearTimeout(xb),xb=window.setTimeout((function(){return qb({type:mb.TimeComplete})}),Cb)}function Mb(){window.clearTimeout(xb)}function Rb(){Nb.context.id=null}function Fb(e){var n=void 0===e?{}:e,r=n.id,i=n.onPointerEnter,o=n.onPointerMove,a=n.onPointerLeave,s=n.onPointerDown,l=n.onMouseEnter,u=n.onMouseMove,c=n.onMouseLeave,d=n.onMouseDown,f=n.onFocus,p=n.onBlur,h=n.onKeyDown,m=n.disabled,v=n.ref,y=n.DEBUG_STYLE,b=String(rd(r)),E=(0,t.useState)(!!y||Gb(b,!0)),T=E[0],w=E[1],C=(0,t.useRef)(null),S=Ss(v,C),x=cd(C,{observe:T});function k(e,t){return"undefined"!=typeof window&&"PointerEvent"in window?e:xs(e,t)}function N(e){return g((function(t){"mouse"===t.pointerType&&e(t)}),"onPointerEvent")}function _(){qb({type:mb.MouseEnter,id:b})}function O(){qb({type:mb.MouseMove,id:b})}function I(){qb({type:mb.MouseLeave})}function D(){Nb.context.id===b&&qb({type:mb.MouseDown})}function L(){window.__REACH_DISABLE_TOOLTIPS||qb({type:mb.Focus,id:b})}function A(){Nb.context.id===b&&qb({type:mb.Blur})}function M(e){"Enter"!==e.key&&" "!==e.key||qb({type:mb.SelectWithKeyboard})}return(0,t.useEffect)((function(){return Ob((function(){w(Gb(b))}))}),[b]),(0,t.useEffect)((function(){var e=ms(C.current);function t(e){"Escape"!==e.key&&"Esc"!==e.key||Nb.value!==hb.Visible||qb({type:mb.SelectWithKeyboard})}return g(t,"listener"),e.addEventListener("keydown",t),function(){return e.removeEventListener("keydown",t)}}),[]),$b({disabled:m,isVisible:T,ref:C}),g(k,"wrapMouseEvent"),g(N,"wrapPointerEventHandler"),g(_,"handleMouseEnter"),g(O,"handleMouseMove"),g(I,"handleMouseLeave"),g(D,"handleMouseDown"),g(L,"handleFocus"),g(A,"handleBlur"),g(M,"handleKeyDown"),[{"aria-describedby":T?lf("tooltip",b):void 0,"data-state":T?"tooltip-visible":"tooltip-hidden","data-reach-tooltip-trigger":"",ref:S,onPointerEnter:xs(i,N(_)),onPointerMove:xs(o,N(O)),onPointerLeave:xs(a,N(I)),onPointerDown:xs(s,N(D)),onMouseEnter:k(l,_),onMouseMove:k(u,O),onMouseLeave:k(c,I),onMouseDown:k(d,D),onFocus:xs(f,L),onBlur:xs(p,A),onKeyDown:xs(h,M)},{id:b,triggerRect:x,isVisible:T},T]}g(Ob,"subscribe"),g(Ib,"notify"),g(Db,"startRestTimer"),g(Lb,"clearRestTimer"),g(Ab,"startLeavingVisibleTimer"),g(Mb,"clearLeavingVisibleTimer"),g(Rb,"clearContextId"),g(Fb,"useTooltip");var Pb=(0,t.forwardRef)((function(e,n){var r=e.children,i=e.label,o=e.ariaLabel,a=e.id,s=e.DEBUG_STYLE,l=sb(e,yb),u=t.Children.only(r),c=Fb({id:a,onPointerEnter:u.props.onPointerEnter,onPointerMove:u.props.onPointerMove,onPointerLeave:u.props.onPointerLeave,onPointerDown:u.props.onPointerDown,onMouseEnter:u.props.onMouseEnter,onMouseMove:u.props.onMouseMove,onMouseLeave:u.props.onMouseLeave,onMouseDown:u.props.onMouseDown,onFocus:u.props.onFocus,onBlur:u.props.onBlur,onKeyDown:u.props.onKeyDown,disabled:u.props.disabled,ref:u.ref,DEBUG_STYLE:s}),d=c[0],f=c[1];return(0,t.createElement)(t.Fragment,null,(0,t.cloneElement)(u,d),(0,t.createElement)(jb,ab({ref:n,label:i,"aria-label":o},f,l)))}));e.aQ=Pb;var jb=(0,t.forwardRef)(g((function(e,n){var r=e.label,i=e.ariaLabel,o=e.isVisible,a=e.id,s=sb(e,bb);return o?(0,t.createElement)(hs,null,(0,t.createElement)(Vb,ab({ref:n,label:r,"aria-label":i,isVisible:o},s,{id:lf("tooltip",String(a))}))):null}),"TooltipPopup")),Vb=(0,t.forwardRef)(g((function(e,n){var r=e.ariaLabel,i=e["aria-label"],o=e.as,a=void 0===o?"div":o,s=e.id,l=e.isVisible,u=e.label,c=e.position,d=void 0===c?Bb:c,f=e.style,p=e.triggerRect,h=sb(e,Eb),m=null!=(i||r),g=(0,t.useRef)(null),v=Ss(n,g),y=cd(g,{observe:l});return(0,t.createElement)(t.Fragment,null,(0,t.createElement)(a,ab({role:m?void 0:"tooltip"},h,{ref:v,"data-reach-tooltip":"",id:m?void 0:s,style:ab({},f,Ub(d,p,y))}),u),m&&(0,t.createElement)(Kc,{role:"tooltip",id:s},i||r))}),"TooltipContent"));function Ub(e,t,n){return n?e(t,n):{visibility:"hidden"}}g(Ub,"getStyles");var Bb=g((function(e,t,n){void 0===n&&(n=8);var r=ob(),i=r.width,o=r.height;if(!e||!t)return{};var a={top:e.top-t.height<0,right:i{var n=e,{isActive:r}=n,i=v(n,["isActive"]);return de("div",m(h({},i),{ref:t,role:"tab","aria-selected":r,className:b("graphiql-tab",r&&"graphiql-tab-active",i.className),children:i.children}))}));zb.displayName="Tab";const Wb=(0,t.forwardRef)(((e,t)=>de(os,m(h({},e),{ref:t,type:"button",className:b("graphiql-tab-button",e.className),children:e.children}))));Wb.displayName="Tab.Button";const Kb=(0,t.forwardRef)(((e,t)=>de(Pb,{label:"Close Tab",children:de(os,m(h({"aria-label":"Close Tab"},e),{ref:t,type:"button",className:b("graphiql-tab-close",e.className),children:de(La,{})}))})));Kb.displayName="Tab.Close";const Qb=Xc(zb,{Button:Wb,Close:Kb});e.aO=Qb;const Xb=(0,t.forwardRef)(((e,t)=>de("div",m(h({},e),{ref:t,role:"tablist",className:b("graphiql-tabs",e.className),children:e.children}))));e.aP=Xb,Xb.displayName="Tabs";var Yb=Object.defineProperty,Jb=g(((e,t)=>Yb(e,"name",{value:t,configurable:!0})),"__name$C");const Zb=X("HistoryContext");function eE(e){var n;const r=ye(),i=(0,t.useRef)(new W(r||new H(null),e.maxHistoryLength||nE)),[o,a]=(0,t.useState)((null==(n=i.current)?void 0:n.queries)||[]),s=(0,t.useCallback)((e=>{let{query:t,variables:n,headers:r,operationName:o}=e;var s;null==(s=i.current)||s.updateHistory(t,n,r,o),a(i.current.queries)}),[]),l=(0,t.useCallback)((e=>{let{query:t,variables:n,headers:r,operationName:o,label:s,favorite:l}=e;i.current.editLabel(t,n,r,o,s,l),a(i.current.queries)}),[]),u=(0,t.useCallback)((e=>{let{query:t,variables:n,headers:r,operationName:o,label:s,favorite:l}=e;i.current.toggleFavorite(t,n,r,o,s,l),a(i.current.queries)}),[]),c=(0,t.useMemo)((()=>({addToHistory:s,editLabel:l,items:o,toggleFavorite:u})),[s,l,o,u]);return de(Zb.Provider,{value:c,children:e.children})}e.X=Zb,g(eE,"HistoryContextProvider"),Jb(eE,"HistoryContextProvider");const tE=Y(Zb);e.Z=tE;const nE=20;var rE=Object.defineProperty,iE=g(((e,t)=>rE(e,"name",{value:t,configurable:!0})),"__name$B");function oE(){const{items:e}=tE({nonNull:!0}),n=e.slice().reverse();return fe("section",{"aria-label":"History",className:"graphiql-history",children:[de("div",{className:"graphiql-history-header",children:"History"}),de("ul",{className:"graphiql-history-items",children:n.map(((e,r)=>fe(t.Fragment,{children:[de(aE,{item:e}),e.favorite&&n[r+1]&&!n[r+1].favorite?de("div",{className:"graphiql-history-item-spacer"}):null]},`${r}:${e.label||e.query}`)))})]})}function aE(e){const{editLabel:n,toggleFavorite:r}=tE({nonNull:!0,caller:aE}),{headerEditor:i,queryEditor:o,variableEditor:a}=oS({nonNull:!0,caller:aE}),s=(0,t.useRef)(null),l=(0,t.useRef)(null),[u,c]=(0,t.useState)(!1);(0,t.useEffect)((()=>{u&&s.current&&s.current.focus()}),[u]);const d=e.item.label||e.item.operationName||sE(e.item.query);return de("li",{className:b("graphiql-history-item",u&&"editable"),children:fe(pe,u?{children:[de("input",{type:"text",defaultValue:e.item.label,ref:s,onKeyDown:t=>{"Esc"===t.key?c(!1):"Enter"===t.key&&(c(!1),n(m(h({},e.item),{label:t.currentTarget.value})))},placeholder:"Type a label"}),de(os,{type:"button",ref:l,onClick:()=>{var t;c(!1),n(m(h({},e.item),{label:null==(t=s.current)?void 0:t.value}))},children:"Save"}),de(os,{type:"button",ref:l,onClick:()=>{c(!1)},children:de(La,{})})]}:{children:[de(os,{type:"button",className:"graphiql-history-item-label",onClick:()=>{var t,n,r;null==o||o.setValue(null!=(t=e.item.query)?t:""),null==a||a.setValue(null!=(n=e.item.variables)?n:""),null==i||i.setValue(null!=(r=e.item.headers)?r:"")},children:d}),de(Pb,{label:"Edit label",children:de(os,{type:"button",className:"graphiql-history-item-action",onClick:e=>{e.stopPropagation(),c(!0)},"aria-label":"Edit label",children:de(Wa,{"aria-hidden":"true"})})}),de(Pb,{label:e.item.favorite?"Remove favorite":"Add favorite",children:de(os,{type:"button",className:"graphiql-history-item-action",onClick:t=>{t.stopPropagation(),r(e.item)},"aria-label":e.item.favorite?"Remove favorite":"Add favorite",children:e.item.favorite?de(es,{"aria-hidden":"true"}):de(ts,{"aria-hidden":"true"})})})]})})}function sE(e){return null==e?void 0:e.split("\n").map((e=>e.replace(/#(.*)/,""))).join(" ").replaceAll("{"," { ").replaceAll("}"," } ").replaceAll(/[\s]{2,}/g," ")}g(oE,"History"),iE(oE,"History"),g(aE,"HistoryItem"),iE(aE,"HistoryItem"),g(sE,"formatQuery"),iE(sE,"formatQuery");var lE=Object.defineProperty,uE=g(((e,t)=>lE(e,"name",{value:t,configurable:!0})),"__name$A");const cE=X("ExecutionContext");function dE(e){let{fetcher:n,getDefaultFieldNames:i,children:o,operationName:a}=e;if(!n)throw new TypeError("The `ExecutionContextProvider` component requires a `fetcher` function to be passed as prop.");const{externalFragments:s,headerEditor:l,queryEditor:u,responseEditor:c,variableEditor:d,updateActiveTabValues:f}=oS({nonNull:!0,caller:dE}),p=tE(),m=fC({getDefaultFieldNames:i,caller:dE}),[g,y]=(0,t.useState)(!1),[b,E]=(0,t.useState)(null),T=(0,t.useRef)(0),w=(0,t.useCallback)((()=>{null==b||b.unsubscribe(),y(!1),E(null)}),[b]),x=(0,t.useCallback)((async()=>{var e,t;if(!u||!c)return;if(b)return void w();const i=uE((e=>{c.setValue(e),f({response:e})}),"setResponse");T.current+=1;const o=T.current;let g=m()||u.getValue();const x=null==d?void 0:d.getValue();let k;try{k=pE({json:x,errorMessageParse:"Variables are invalid JSON",errorMessageType:"Variables are not a JSON object."})}catch(e){return void i(e instanceof Error?e.message:`${e}`)}const N=null==l?void 0:l.getValue();let _;try{_=pE({json:N,errorMessageParse:"Headers are invalid JSON",errorMessageType:"Headers are not a JSON object."})}catch(e){return void i(e instanceof Error?e.message:`${e}`)}if(s){const e=u.documentAST?_o(u.documentAST,s):[];e.length>0&&(g+="\n"+e.map((e=>(0,r.print)(e))).join("\n"))}i(""),y(!0);const O=null!=(e=null!=a?a:u.operationName)?e:void 0;null==p||p.addToHistory({query:g,variables:x,headers:N,operationName:O});try{let e={data:{}};const r=uE((t=>{if(o!==T.current)return;let n=!!Array.isArray(t)&&t;if(!n&&"object"==typeof t&&null!==t&&"hasNext"in t&&(n=[t]),n){const t={data:e.data},r=[...(null==e?void 0:e.errors)||[],...n.flatMap((e=>e.errors)).filter(Boolean)];r.length&&(t.errors=r);for(const r of n){const n=r,{path:i,data:o,errors:a}=n,s=v(n,["path","data","errors"]);if(i){if(!o)throw new Error(`Expected part to contain a data property, but got ${r}`);Qo(t.data,i,o,{merge:!0})}else o&&(t.data=o);e=h(h({},t),s)}y(!1),i(L(e))}else{const e=L(t);y(!1),i(e)}}),"handleResponse"),a=n({query:g,variables:k,operationName:O},{headers:null!=_?_:void 0,documentAST:null!=(t=u.documentAST)?t:void 0}),s=await Promise.resolve(a);if(C(s))E(s.subscribe({next(e){r(e)},error(e){y(!1),e&&i(D(e)),E(null)},complete(){y(!1),E(null)}}));else if(S(s)){E({unsubscribe:()=>{var e,t;return null==(t=(e=s[Symbol.asyncIterator]()).return)?void 0:t.call(e)}});for await(const e of s)r(e);y(!1),E(null)}else r(s)}catch(e){y(!1),i(D(e)),E(null)}}),[m,s,n,l,p,a,u,c,w,b,f,d]),k=Boolean(b),N=(0,t.useMemo)((()=>({isFetching:g,isSubscribed:k,operationName:null!=a?a:null,run:x,stop:w})),[g,k,a,x,w]);return de(cE.Provider,{value:N,children:o})}e.r=cE,g(dE,"ExecutionContextProvider"),uE(dE,"ExecutionContextProvider");const fE=Y(cE);function pE(e){let t,{json:n,errorMessageParse:r,errorMessageType:i}=e;try{t=n&&""!==n.trim()?JSON.parse(n):void 0}catch(e){throw new Error(`${r}: ${e instanceof Error?e.message:e}.`)}const o="object"==typeof t&&null!==t&&!Array.isArray(t);if(void 0!==t&&!o)throw new Error(i);return t}e.v=fE,g(pE,"tryParseJsonObject"),uE(pE,"tryParseJsonObject");var hE=Object.defineProperty,mE=g(((e,t)=>hE(e,"name",{value:t,configurable:!0})),"__name$z");const gE="graphiql",vE="sublime";let yE=!1;"object"==typeof window&&(yE=0===window.navigator.platform.toLowerCase().indexOf("mac"));const bE={[yE?"Cmd-F":"Ctrl-F"]:"findPersistent","Cmd-G":"findPersistent","Ctrl-G":"findPersistent","Ctrl-Left":"goSubwordLeft","Ctrl-Right":"goSubwordRight","Alt-Left":"goGroupLeft","Alt-Right":"goGroupRight"};async function EE(e,t){const r=await Promise.resolve().then(n.t.bind(n,535,23)).then((function(e){return e.c})).then((e=>"function"==typeof e?e:e.default));return await Promise.all(!1===(null==t?void 0:t.useCommonAddons)?e:[Promise.resolve().then(n.t.bind(n,6980,23)).then((function(e){return e.s})),Promise.resolve().then(n.t.bind(n,9171,23)).then((function(e){return e.m})),Promise.resolve().then(n.t.bind(n,5728,23)).then((function(e){return e.c})),Promise.resolve().then(n.t.bind(n,4468,23)).then((function(e){return e.b})),Promise.resolve().then(n.t.bind(n,8419,23)).then((function(e){return e.f})),Promise.resolve().then(n.t.bind(n,4054,23)).then((function(e){return e.l})),Promise.resolve().then(n.t.bind(n,9407,23)).then((function(e){return e.s})),Promise.resolve().then(n.t.bind(n,4471,23)).then((function(e){return e.j})),Promise.resolve().then(n.t.bind(n,8058,23)).then((function(e){return e.d})),Promise.resolve().then(n.t.bind(n,2568,23)).then((function(e){return e.s})),...e]),r}g(EE,"importCodeMirror"),mE(EE,"importCodeMirror");var TE=g((function(){var e=document.getSelection();if(!e.rangeCount)return function(){};for(var t=document.activeElement,n=[],r=0;rNE(e,"name",{value:t,configurable:!0})),"__name$y");const OE=_E((e=>e?(0,r.print)(e):""),"printDefault");function IE(e){let{field:t}=e;if(!("defaultValue"in t)||void 0===t.defaultValue)return null;const n=(0,r.astFromValue)(t.defaultValue,t.type);return n?fe(pe,{children:[" = ",de("span",{className:"graphiql-doc-explorer-default-value",children:OE(n)})]}):null}g(IE,"DefaultValue"),_E(IE,"DefaultValue");var DE=Object.defineProperty,LE=g(((e,t)=>DE(e,"name",{value:t,configurable:!0})),"__name$x");const AE=X("SchemaContext");function ME(e){if(!e.fetcher)throw new TypeError("The `SchemaContextProvider` component requires a `fetcher` function to be passed as prop.");const{initialHeaders:n,headerEditor:i}=oS({nonNull:!0,caller:ME}),[o,a]=(0,t.useState)(),[s,l]=(0,t.useState)(!1),[u,c]=(0,t.useState)(null),d=(0,t.useRef)(0);(0,t.useEffect)((()=>{a((0,r.isSchema)(e.schema)||null===e.schema||void 0===e.schema?e.schema:void 0),d.current++}),[e.schema]);const f=(0,t.useRef)(n);(0,t.useEffect)((()=>{i&&(f.current=i.getValue())}));const{introspectionQuery:p,introspectionQueryName:h,introspectionQuerySansSubscriptions:m}=FE({inputValueDeprecation:e.inputValueDeprecation,introspectionQueryName:e.introspectionQueryName,schemaDescription:e.schemaDescription}),{fetcher:v,onSchemaChange:y,dangerouslyAssumeSchemaIsValid:b,children:E}=e,w=(0,t.useCallback)((()=>{if((0,r.isSchema)(e.schema)||null===e.schema)return;const t=++d.current,n=e.schema;async function i(){if(n)return n;const e=PE(f.current);if(!e.isValidJSON)return void c("Introspection failed as headers are invalid.");const t=e.headers?{headers:e.headers}:{},r=k(v({query:p,operationName:h},t));if(!T(r))return void c("Fetcher did not return a Promise for introspection.");l(!0),c(null);let i=await r;if("object"!=typeof i||null===i||!("data"in i)){const e=k(v({query:m,operationName:h},t));if(!T(e))throw new Error("Fetcher did not return a Promise for introspection.");i=await e}if(l(!1),(null==i?void 0:i.data)&&"__schema"in i.data)return i.data;const o="string"==typeof i?i:L(i);c(o)}g(i,"fetchIntrospectionData"),LE(i,"fetchIntrospectionData"),i().then((e=>{if(t===d.current&&e)try{const t=(0,r.buildClientSchema)(e);a(t),null==y||y(t)}catch(e){c(D(e))}})).catch((e=>{t===d.current&&(c(D(e)),l(!1))}))}),[v,h,p,m,y,e.schema]);(0,t.useEffect)((()=>{w()}),[w]),(0,t.useEffect)((()=>{function e(e){e.ctrlKey&&"R"===e.key&&w()}return g(e,"triggerIntrospection"),LE(e,"triggerIntrospection"),window.addEventListener("keydown",e),()=>window.removeEventListener("keydown",e)}));const C=(0,t.useMemo)((()=>!o||b?[]:(0,r.validateSchema)(o)),[o,b]),S=(0,t.useMemo)((()=>({fetchError:u,introspect:w,isFetching:s,schema:o,validationErrors:C})),[u,w,s,o,C]);return de(AE.Provider,{value:S,children:E})}e.a4=AE,g(ME,"SchemaContextProvider"),LE(ME,"SchemaContextProvider");const RE=Y(AE);function FE(e){let{inputValueDeprecation:n,introspectionQueryName:i,schemaDescription:o}=e;return(0,t.useMemo)((()=>{const e=i||"IntrospectionQuery";let t=(0,r.getIntrospectionQuery)({inputValueDeprecation:n,schemaDescription:o});i&&(t=t.replace("query IntrospectionQuery",`query ${e}`));const a=t.replace("subscriptionType { name }","");return{introspectionQueryName:e,introspectionQuery:t,introspectionQuerySansSubscriptions:a}}),[n,i,o])}function PE(e){let t=null,n=!0;try{e&&(t=JSON.parse(e))}catch{n=!1}return{headers:t,isValidJSON:n}}e.a6=RE,g(FE,"useIntrospectionQuery"),LE(FE,"useIntrospectionQuery"),g(PE,"parseHeaderString"),LE(PE,"parseHeaderString");var jE=Object.defineProperty,VE=g(((e,t)=>jE(e,"name",{value:t,configurable:!0})),"__name$w");const UE={name:"Docs"},BE=X("ExplorerContext");function $E(e){const{schema:n,validationErrors:i}=RE({nonNull:!0,caller:$E}),[o,a]=(0,t.useState)([UE]),s=(0,t.useCallback)((e=>{a((t=>t.at(-1).def===e.def?t:[...t,e]))}),[]),l=(0,t.useCallback)((()=>{a((e=>e.length>1?e.slice(0,-1):e))}),[]),u=(0,t.useCallback)((()=>{a((e=>1===e.length?e:[UE]))}),[]);(0,t.useEffect)((()=>{null==n||i.length>0?u():a((e=>{if(1===e.length)return e;const t=[UE];let i=null;for(const o of e)if(o!==UE)if(o.def)if((0,r.isNamedType)(o.def)){const e=n.getType(o.def.name);if(!e)break;t.push({name:o.name,def:e}),i=e}else{if(null===i)break;if((0,r.isObjectType)(i)||(0,r.isInputObjectType)(i)){const e=i.getFields()[o.name];if(!e)break;t.push({name:o.name,def:e})}else{if((0,r.isScalarType)(i)||(0,r.isEnumType)(i)||(0,r.isInterfaceType)(i)||(0,r.isUnionType)(i))break;{const e=i;if(!e.args.find((e=>e.name===o.name)))break;t.push({name:o.name,def:e})}}}else i=null,t.push(o);return t}))}),[u,n,i]);const c=(0,t.useMemo)((()=>({explorerNavStack:o,push:s,pop:l,reset:u})),[o,s,l,u]);return de(BE.Provider,{value:c,children:e.children})}e.z=BE,g($E,"ExplorerContextProvider"),VE($E,"ExplorerContextProvider");const qE=Y(BE);e.U=qE;var HE=Object.defineProperty,GE=g(((e,t)=>HE(e,"name",{value:t,configurable:!0})),"__name$v");function zE(e,t){return(0,r.isNonNullType)(e)?fe(pe,{children:[zE(e.ofType,t),"!"]}):(0,r.isListType)(e)?fe(pe,{children:["[",zE(e.ofType,t),"]"]}):t(e)}g(zE,"renderType"),GE(zE,"renderType");var WE=Object.defineProperty,KE=g(((e,t)=>WE(e,"name",{value:t,configurable:!0})),"__name$u");function QE(e){const{push:t}=qE({nonNull:!0,caller:QE});return e.type?zE(e.type,(e=>de("a",{className:"graphiql-doc-explorer-type-name",onClick:n=>{n.preventDefault(),t({name:e.name,def:e})},href:"#",children:e.name}))):null}g(QE,"TypeLink"),KE(QE,"TypeLink");var XE=Object.defineProperty,YE=g(((e,t)=>XE(e,"name",{value:t,configurable:!0})),"__name$t");function JE(e){let{arg:t,showDefaultValue:n,inline:r}=e;const i=fe("span",{children:[de("span",{className:"graphiql-doc-explorer-argument-name",children:t.name}),": ",de(QE,{type:t.type}),!1!==n&&de(IE,{field:t})]});return r?i:fe("div",{className:"graphiql-doc-explorer-argument",children:[i,t.description?de(rb,{type:"description",children:t.description}):null,t.deprecationReason?fe("div",{className:"graphiql-doc-explorer-argument-deprecation",children:[de("div",{className:"graphiql-doc-explorer-argument-deprecation-label",children:"Deprecated"}),de(rb,{type:"deprecation",children:t.deprecationReason})]}):null]})}g(JE,"Argument"),YE(JE,"Argument");var ZE=Object.defineProperty,eT=g(((e,t)=>ZE(e,"name",{value:t,configurable:!0})),"__name$s");function tT(e){return e.children?fe("div",{className:"graphiql-doc-explorer-deprecation",children:[de("div",{className:"graphiql-doc-explorer-deprecation-label",children:"Deprecated"}),de(rb,{type:"deprecation",onlyShowFirstChild:!0,children:e.children})]}):null}g(tT,"DeprecationReason"),eT(tT,"DeprecationReason");var nT=Object.defineProperty,rT=g(((e,t)=>nT(e,"name",{value:t,configurable:!0})),"__name$r");function iT(e){let{directive:t}=e;return fe("span",{className:"graphiql-doc-explorer-directive",children:["@",t.name.value]})}g(iT,"Directive"),rT(iT,"Directive");var oT=Object.defineProperty,aT=g(((e,t)=>oT(e,"name",{value:t,configurable:!0})),"__name$q");function sT(e){const t=lT[e.title];return fe("div",{children:[fe("div",{className:"graphiql-doc-explorer-section-title",children:[de(t,{}),e.title]}),de("div",{className:"graphiql-doc-explorer-section-content",children:e.children})]})}g(sT,"ExplorerSection"),aT(sT,"ExplorerSection");const lT={Arguments:_a,"Deprecated Arguments":Ma,"Deprecated Enum Values":Ra,"Deprecated Fields":Fa,Directives:Pa,"Enum Values":Ua,Fields:Ba,Implements:qa,Implementations:rs,"Possible Types":rs,"Root Types":Ja,Type:rs,"All Schema Types":rs};var uT=Object.defineProperty,cT=g(((e,t)=>uT(e,"name",{value:t,configurable:!0})),"__name$p");function dT(e){return fe(pe,{children:[e.field.description?de(rb,{type:"description",children:e.field.description}):null,de(tT,{children:e.field.deprecationReason}),de(sT,{title:"Type",children:de(QE,{type:e.field.type})}),de(fT,{field:e.field}),de(pT,{field:e.field})]})}function fT(e){let{field:n}=e;const[r,i]=(0,t.useState)(!1);if(!("args"in n))return null;const o=[],a=[];for(const e of n.args)e.deprecationReason?a.push(e):o.push(e);return fe(pe,{children:[o.length>0?de(sT,{title:"Arguments",children:o.map((e=>de(JE,{arg:e},e.name)))}):null,a.length>0?r||0===o.length?de(sT,{title:"Deprecated Arguments",children:a.map((e=>de(JE,{arg:e},e.name)))}):de(as,{type:"button",onClick:()=>{i(!0)},children:"Show Deprecated Arguments"}):null]})}function pT(e){let{field:t}=e;var n;const r=(null==(n=t.astNode)?void 0:n.directives)||[];return r&&0!==r.length?de(sT,{title:"Directives",children:r.map((e=>de("div",{children:de(iT,{directive:e})},e.name.value)))}):null}g(dT,"FieldDocumentation"),cT(dT,"FieldDocumentation"),g(fT,"Arguments"),cT(fT,"Arguments"),g(pT,"Directives"),cT(pT,"Directives");var hT=Object.defineProperty,mT=g(((e,t)=>hT(e,"name",{value:t,configurable:!0})),"__name$o");function gT(e){var t,n,r,i;const o=e.schema.getQueryType(),a=null==(n=(t=e.schema).getMutationType)?void 0:n.call(t),s=null==(i=(r=e.schema).getSubscriptionType)?void 0:i.call(r),l=e.schema.getTypeMap(),u=[null==o?void 0:o.name,null==a?void 0:a.name,null==s?void 0:s.name];return fe(pe,{children:[de(rb,{type:"description",children:e.schema.description||"A GraphQL schema provides a root type for each kind of operation."}),fe(sT,{title:"Root Types",children:[o?fe("div",{children:[de("span",{className:"graphiql-doc-explorer-root-type",children:"query"}),": ",de(QE,{type:o})]}):null,a&&fe("div",{children:[de("span",{className:"graphiql-doc-explorer-root-type",children:"mutation"}),": ",de(QE,{type:a})]}),s&&fe("div",{children:[de("span",{className:"graphiql-doc-explorer-root-type",children:"subscription"}),": ",de(QE,{type:s})]})]}),de(sT,{title:"All Schema Types",children:l&&de("div",{children:Object.values(l).map((e=>u.includes(e.name)||e.name.startsWith("__")?null:de("div",{children:de(QE,{type:e})},e.name)))})})]})}function vT(e,n){var r=(0,t.useRef)(!1);(0,t.useEffect)((function(){r.current?e():r.current=!0}),n)}function yT(e,t){if(null==e)return{};var n,r,i={},o=Object.keys(e);for(r=0;r=0||(i[n]=e[n]);return i}function bT(){return bT=Object.assign||function(e){for(var t=1;tl&&e.push({highlight:!1,start:l,end:u}),o.index===s.lastIndex&&s.lastIndex++}return e}),[])}function CT(e){var t=e.chunksToHighlight,n=e.totalLength,r=[];if(0===t.length)o(0,n,!1);else{var i=0;t.forEach((function(e){o(i,e.start,!1),o(e.start,e.end,!0),i=e.end})),o(i,n,!1)}return r;function o(e,t,n){t-e>0&&r.push({start:e,end:t,highlight:n})}}function ST(e){return e}function xT(e){return e.replace(/[-[\]/{}()*+?.\\^$|]/g,"\\$&")}g(gT,"SchemaDocumentation"),mT(gT,"SchemaDocumentation"),g(vT,"useUpdateEffect"),g(yT,"_objectWithoutPropertiesLoose"),g(bT,"_extends"),g(ET,"findAll"),g(TT,"combineChunks"),g(wT,"defaultFindChunks"),g(CT,"fillInChunks"),g(ST,"defaultSanitize"),g(xT,"escapeRegExpFn");var kT,NT,_T,OT,IT,DT={combineChunks:TT,fillInChunks:CT,findAll:ET,findChunks:wT},LT=["onSelect","openOnFocus","children","as","aria-label","aria-labelledby"],AT=["as","selectOnClick","autocomplete","onClick","onChange","onKeyDown","onBlur","onFocus","value"],MT=["as","children","portal","onKeyDown","onBlur","position"],RT=["persistSelection","as"],FT=["as","children","index","value","onClick"],PT="IDLE",jT="SUGGESTING",VT="NAVIGATING",UT="INTERACTING",BT="CLEAR",$T="CHANGE",qT="INITIAL_CHANGE",HT="NAVIGATE",GT="SELECT_WITH_KEYBOARD",zT="SELECT_WITH_CLICK",WT="ESCAPE",KT="BLUR",QT="INTERACT",XT="FOCUS",YT="OPEN_WITH_BUTTON",JT="OPEN_WITH_INPUT_CLICK",ZT="CLOSE_WITH_BUTTON",ew={initial:PT,states:(IT={},IT[PT]={on:(kT={},kT[KT]=PT,kT[BT]=PT,kT[$T]=jT,kT[qT]=PT,kT[XT]=jT,kT[HT]=VT,kT[YT]=jT,kT[JT]=jT,kT)},IT[jT]={on:(NT={},NT[$T]=jT,NT[XT]=jT,NT[HT]=VT,NT[BT]=PT,NT[WT]=PT,NT[KT]=PT,NT[zT]=PT,NT[QT]=UT,NT[ZT]=PT,NT)},IT[VT]={on:(_T={},_T[$T]=jT,_T[XT]=jT,_T[BT]=PT,_T[KT]=PT,_T[WT]=PT,_T[HT]=VT,_T[zT]=PT,_T[GT]=PT,_T[ZT]=PT,_T[QT]=UT,_T)},IT[UT]={on:(OT={},OT[BT]=PT,OT[$T]=jT,OT[XT]=jT,OT[KT]=PT,OT[WT]=PT,OT[HT]=VT,OT[ZT]=PT,OT[zT]=PT,OT)},IT)},tw=g((function(e,t){var n=bT({},e,{lastEventType:t.type});switch(t.type){case $T:case qT:return bT({},n,{navigationValue:null,value:t.value});case HT:case YT:case JT:return bT({},n,{navigationValue:rw(n,t)});case BT:return bT({},n,{value:"",navigationValue:null});case KT:case WT:return bT({},n,{navigationValue:null});case zT:return bT({},n,{value:t.isControlled?e.value:t.value,navigationValue:null});case GT:return bT({},n,{value:t.isControlled?e.value:e.navigationValue,navigationValue:null});case ZT:return bT({},n,{navigationValue:null});case QT:return n;case XT:return bT({},n,{navigationValue:rw(n,t)});default:return n}}),"reducer");function nw(e){return[jT,VT,UT].includes(e)}function rw(e,t){return t.value?t.value:t.persistSelection?e.value:null}g(nw,"popoverIsExpanded"),g(rw,"findNavigationValue");var iw=zd(),ow=af(0,{}),aw=af(0,{}),sw=(0,t.forwardRef)((function(e,n){var r,i=e.onSelect,o=e.openOnFocus,a=void 0!==o&&o,s=e.children,l=e.as,u=void 0===l?"div":l,c=e["aria-label"],d=e["aria-labelledby"],f=yT(e,LT),p=Kd(),h=p[0],m=p[1],g=(0,t.useRef)(),v=(0,t.useRef)(),y=(0,t.useRef)(),b=(0,t.useRef)(!1),E=(0,t.useRef)(!1),T=gw(ew,tw,{value:"",navigationValue:null}),w=T[0],C=T[1],S=T[2];pw(C.lastEventType,g);var x=rd(f.id),k=x?lf("listbox",x):"listbox",N=(0,t.useRef)(!1),_=nw(w),O={ariaLabel:c,ariaLabelledby:d,autocompletePropRef:b,buttonRef:y,comboboxId:x,data:C,inputRef:g,isExpanded:_,listboxId:k,onSelect:i||bs,openOnFocus:a,persistSelectionRef:E,popoverRef:v,state:w,transition:S,isControlledRef:N};return(0,t.createElement)(Xd,{context:iw,items:h,set:m},(0,t.createElement)(ow.Provider,{value:O},(0,t.createElement)(u,bT({},f,{"data-reach-combobox":"","data-state":yw(w),"data-expanded":_||void 0,ref:n}),vs(s)?s({id:x,isExpanded:_,navigationValue:null!=(r=C.navigationValue)?r:null,state:w}):s)))})),lw=(0,t.forwardRef)((function(e,n){var r=e.as,i=void 0===r?"input":r,o=e.selectOnClick,a=void 0!==o&&o,s=e.autocomplete,l=void 0===s||s,u=e.onClick,c=e.onChange,d=e.onKeyDown,f=e.onBlur,p=e.onFocus,h=e.value,m=yT(e,AT),v=(0,t.useRef)(h).current,y=(0,t.useRef)(!1);vT((function(){y.current=!0}),[h]);var b=(0,t.useContext)(ow),E=b.data,T=E.navigationValue,w=E.value,C=E.lastEventType,S=b.inputRef,x=b.state,k=b.transition,N=b.listboxId,_=b.autocompletePropRef,O=b.openOnFocus,I=b.isExpanded,D=b.ariaLabel,L=b.ariaLabelledby,A=b.persistSelectionRef,M=b.isControlledRef,R=Ss(S,n),F=(0,t.useRef)(!1),P=hw(),j=mw(),V=void 0!==h;(0,t.useEffect)((function(){M.current=V}),[V]),us((function(){_.current=l}),[l,_]);var U=(0,t.useCallback)((function(e){""===e.trim()?k(BT,{isControlled:V}):e!==v||y.current?k($T,{value:e}):k(qT,{value:e})}),[v,k,V]);function B(e){var t=e.target.value;V||U(t)}function $(){a&&(F.current=!0),O&&C!==zT&&k(XT,{persistSelection:A.current})}function q(){var e;F.current&&(F.current=!1,null==(e=S.current)||e.select()),O&&x===PT&&k(JT)}(0,t.useEffect)((function(){!V||h===w||""===h.trim()&&""===(w||"").trim()||U(h)}),[h,U,V,w]),g(B,"handleChange"),g($,"handleFocus"),g(q,"handleClick");var H=!l||x!==VT&&x!==UT?h||w:T||h||w;return(0,t.createElement)(i,bT({"aria-activedescendant":T?String(vw(T)):void 0,"aria-autocomplete":"both","aria-controls":N,"aria-expanded":I,"aria-haspopup":"listbox","aria-label":D,"aria-labelledby":D?void 0:L,role:"combobox"},m,{"data-reach-combobox-input":"","data-state":yw(x),ref:R,onBlur:xs(f,j),onChange:xs(c,B),onClick:xs(u,q),onFocus:xs(p,$),onKeyDown:xs(d,P),value:H||""}))})),uw=(0,t.forwardRef)((function(e,n){var r=e.as,i=void 0===r?"div":r,o=e.children,a=e.portal,s=void 0===a||a,l=e.onKeyDown,u=e.onBlur,c=e.position,d=void 0===c?Ud:c,f=yT(e,MT),p=(0,t.useContext)(ow),h=p.popoverRef,m=p.inputRef,g=p.isExpanded,v=p.state,y=Ss(h,n),b=hw(),E=mw(),T={"data-reach-combobox-popover":"","data-state":yw(v),onKeyDown:xs(l,b),onBlur:xs(u,E),hidden:!g,tabIndex:-1,children:o};return s?(0,t.createElement)(Rd,bT({as:i},f,{ref:y,"data-expanded":g||void 0,position:d,targetRef:m,unstable_skipInitialPortalRender:!0},T)):(0,t.createElement)(i,bT({ref:y},f,T))})),cw=(0,t.forwardRef)((function(e,n){var r=e.persistSelection,i=void 0!==r&&r,o=e.as,a=void 0===o?"ul":o,s=yT(e,RT),l=(0,t.useContext)(ow),u=l.persistSelectionRef,c=l.listboxId;return i&&(u.current=!0),(0,t.createElement)(a,bT({role:"listbox"},s,{ref:n,"data-reach-combobox-list":"",id:c}))})),dw=(0,t.forwardRef)((function(e,n){var r=e.as,i=void 0===r?"li":r,o=e.children,a=e.index,s=e.value,l=e.onClick,u=yT(e,FT),c=(0,t.useContext)(ow),d=c.onSelect,f=c.data.navigationValue,p=c.transition,h=c.isControlledRef,m=uf((0,t.useRef)(null),null),v=m[0],y=m[1],b=Wd((0,t.useMemo)((function(){return{element:v,value:s}}),[s,v]),iw,a),E=Ss(n,y),T=f===s,w=g((function(){d&&d(s),p(zT,{value:s,isControlled:h.current})}),"handleClick");return(0,t.createElement)(aw.Provider,{value:{value:s,index:b}},(0,t.createElement)(i,bT({"aria-selected":T,role:"option"},u,{"data-reach-combobox-option":"",ref:E,id:String(vw(s)),"data-highlighted":T?"":void 0,tabIndex:-1,onClick:xs(l,w)}),o?vs(o)?o({value:s,index:b}):o:(0,t.createElement)(fw,null)))}));function fw(){var e=(0,t.useContext)(aw).value,n=(0,t.useContext)(ow).data.value,r=(0,t.useMemo)((function(){return DT.findAll({searchWords:bw(n||"").split(/\s+/),textToHighlight:e})}),[n,e]);return(0,t.createElement)(t.Fragment,null,r.length?r.map((function(n,r){var i=e.slice(n.start,n.end);return(0,t.createElement)("span",{key:r,"data-reach-combobox-option-text":"","data-user-value":!!n.highlight||void 0,"data-suggested-value":!n.highlight||void 0},i)})):e)}function pw(e,t){us((function(){var n;e!==HT&&e!==WT&&e!==zT&&e!==YT||null==(n=t.current)||n.focus()}),[t,e])}function hw(){var e=(0,t.useContext)(ow),n=e.data.navigationValue,r=e.onSelect,i=e.state,o=e.transition,a=e.autocompletePropRef,s=e.persistSelectionRef,l=e.isControlledRef,u=Qd(iw);return g((function(e){var t=u.findIndex((function(e){return e.value===n}));function c(){return t===u.length-1?a.current?null:f():u[(t+1)%u.length]}function d(){return 0===t?a.current?null:p():-1===t?p():u[(t-1+u.length)%u.length]}function f(){return u[0]}function p(){return u[u.length-1]}switch(g(c,"getNextOption"),g(d,"getPreviousOption"),g(f,"getFirstOption"),g(p,"getLastOption"),e.key){case"ArrowDown":if(e.preventDefault(),!u||!u.length)return;if(i===PT)o(HT,{persistSelection:s.current});else{var h=c();o(HT,{value:h?h.value:null})}break;case"ArrowUp":if(e.preventDefault(),!u||0===u.length)return;if(i===PT)o(HT);else{var m=d();o(HT,{value:m?m.value:null})}break;case"Home":case"PageUp":if(e.preventDefault(),!u||0===u.length)return;i===PT?o(HT):o(HT,{value:f().value});break;case"End":case"PageDown":if(e.preventDefault(),!u||0===u.length)return;i===PT?o(HT):o(HT,{value:p().value});break;case"Escape":i!==PT&&o(WT);break;case"Enter":i===VT&&null!==n&&(e.preventDefault(),r&&r(n),o(GT,{isControlled:l.current}))}}),"handleKeyDown")}function mw(){var e=(0,t.useContext)(ow),n=e.state,r=e.transition,i=e.popoverRef,o=e.inputRef,a=e.buttonRef;return g((function(e){var t=i.current,s=o.current,l=a.current,u=e.relatedTarget;u!==s&&u!==l&&t&&(t.contains(u)?n!==UT&&r(QT):r(KT))}),"handleBlur")}function gw(e,n,r){var i=(0,t.useState)(e.initial),o=i[0],a=i[1],s=(0,t.useReducer)(n,r),l=s[0],u=s[1];return[o,l,g((function(t,n){void 0===n&&(n={});var r=e.states[o],i=r&&r.on[t];if(i)return u(bT({type:t,state:o,nextState:o},n)),void a(i)}),"transition")]}function vw(e){var t=0;if(0===e.length)return t;for(var n=0;nEw(e,"name",{value:t,configurable:!0})),"__name$n");function ww(e,t){let n;return function(){for(var r=arguments.length,i=new Array(r),o=0;o{n=null,t(...i)}),e)}}g(ww,"debounce"),Tw(ww,"debounce");var Cw=Object.defineProperty,Sw=g(((e,t)=>Cw(e,"name",{value:t,configurable:!0})),"__name$m");function xw(){const{explorerNavStack:e,push:n}=qE({nonNull:!0,caller:xw}),i=(0,t.useRef)(null),o=(0,t.useRef)(null),a=kw(),[s,l]=(0,t.useState)(""),[u,c]=(0,t.useState)(a(s)),d=(0,t.useMemo)((()=>ww(200,(e=>{c(a(e))}))),[a]);(0,t.useEffect)((()=>{d(s)}),[d,s]),(0,t.useEffect)((()=>{function e(e){var t;e.metaKey&&"k"===e.key&&(null==(t=i.current)||t.focus())}return g(e,"handleKeyDown"),Sw(e,"handleKeyDown"),window.addEventListener("keydown",e),()=>window.removeEventListener("keydown",e)}),[]);const f=e.at(-1);return 1===e.length||(0,r.isObjectType)(f.def)||(0,r.isInterfaceType)(f.def)||(0,r.isInputObjectType)(f.def)?fe(sw,{"aria-label":`Search ${f.name}...`,onSelect:e=>{const t=e;n("field"in t?{name:t.field.name,def:t.field}:{name:t.type.name,def:t.type})},children:[fe("div",{className:"graphiql-doc-explorer-search-input",onClick:()=>{i.current&&i.current.focus()},children:[de(Ga,{}),de(lw,{autocomplete:!1,onChange:e=>{l(e.target.value)},onKeyDown:e=>{if(!e.isDefaultPrevented()){const e=o.current;if(!e)return;window.requestAnimationFrame((()=>{const t=e.querySelector("[aria-selected=true]");if(!(t instanceof HTMLElement))return;const n=t.offsetTop-e.scrollTop,r=e.scrollTop+e.clientHeight-(t.offsetTop+t.clientHeight);r<0&&(e.scrollTop-=r),n<0&&(e.scrollTop+=n)}))}e.stopPropagation()},placeholder:"⌘ K",ref:i,value:s})]}),de(uw,{portal:!1,ref:o,children:fe(cw,{children:[u.within.map(((e,t)=>de(dw,{index:t,value:e,children:de(Ow,{field:e.field,argument:e.argument})},`within-${t}`))),u.within.length>0&&u.types.length+u.fields.length>0?de("div",{className:"graphiql-doc-explorer-search-divider",children:"Other results"}):null,u.types.map(((e,t)=>de(dw,{index:u.within.length+t,value:e,children:de(_w,{type:e.type})},`type-${t}`))),u.fields.map(((e,t)=>fe(dw,{index:u.within.length+u.types.length+t,value:e,children:[de(_w,{type:e.type}),".",de(Ow,{field:e.field,argument:e.argument})]},`field-${t}`))),u.within.length+u.types.length+u.fields.length===0?de("div",{className:"graphiql-doc-explorer-search-empty",children:"No results found"}):null]})})]}):null}function kw(e){const{explorerNavStack:n}=qE({nonNull:!0,caller:e||kw}),{schema:i}=RE({nonNull:!0,caller:e||kw}),o=n.at(-1);return(0,t.useCallback)((e=>{const t={within:[],types:[],fields:[]};if(!i)return t;const n=o.def,a=i.getTypeMap();let s=Object.keys(a);n&&(s=s.filter((e=>e!==n.name)),s.unshift(n.name));for(const i of s){if(t.within.length+t.types.length+t.fields.length>=100)break;const o=a[i];if(n!==o&&Nw(i,e)&&t.types.push({type:o}),!(0,r.isObjectType)(o)&&!(0,r.isInterfaceType)(o)&&!(0,r.isInputObjectType)(o))continue;const s=o.getFields();for(const r in s){const i=s[r];let a;if(!Nw(r,e)){if(!("args"in i))continue;if(a=i.args.filter((t=>Nw(t.name,e))),0===a.length)continue}t[n===o?"within":"fields"].push(...a?a.map((e=>({type:o,field:i,argument:e}))):[{type:o,field:i}])}}return t}),[o.def,i])}function Nw(e,t){try{const n=t.replaceAll(/[^_0-9A-Za-z]/g,(e=>"\\"+e));return-1!==e.search(new RegExp(n,"i"))}catch{return e.toLowerCase().includes(t.toLowerCase())}}function _w(e){return de("span",{className:"graphiql-doc-explorer-search-type",children:e.type.name})}function Ow(e){return fe(pe,{children:[de("span",{className:"graphiql-doc-explorer-search-field",children:e.field.name}),e.argument?fe(pe,{children:["(",de("span",{className:"graphiql-doc-explorer-search-argument",children:e.argument.name}),":"," ",zE(e.argument.type,(e=>de(_w,{type:e}))),")"]}):null]})}g(xw,"Search"),Sw(xw,"Search"),g(kw,"useSearchResults"),Sw(kw,"useSearchResults"),g(Nw,"isMatch"),Sw(Nw,"isMatch"),g(_w,"Type"),Sw(_w,"Type"),g(Ow,"Field$1"),Sw(Ow,"Field");var Iw=Object.defineProperty,Dw=g(((e,t)=>Iw(e,"name",{value:t,configurable:!0})),"__name$l");function Lw(e){const{push:t}=qE({nonNull:!0});return de("a",{className:"graphiql-doc-explorer-field-name",onClick:n=>{n.preventDefault(),t({name:e.field.name,def:e.field})},href:"#",children:e.field.name})}g(Lw,"FieldLink"),Dw(Lw,"FieldLink");var Aw=Object.defineProperty,Mw=g(((e,t)=>Aw(e,"name",{value:t,configurable:!0})),"__name$k");function Rw(e){return(0,r.isNamedType)(e.type)?fe(pe,{children:[e.type.description?de(rb,{type:"description",children:e.type.description}):null,de(Fw,{type:e.type}),de(Pw,{type:e.type}),de(Vw,{type:e.type}),de(Bw,{type:e.type})]}):null}function Fw(e){let{type:t}=e;return(0,r.isObjectType)(t)&&t.getInterfaces().length>0?de(sT,{title:"Implements",children:t.getInterfaces().map((e=>de("div",{children:de(QE,{type:e})},e.name)))}):null}function Pw(e){let{type:n}=e;const[i,o]=(0,t.useState)(!1);if(!(0,r.isObjectType)(n)&&!(0,r.isInterfaceType)(n)&&!(0,r.isInputObjectType)(n))return null;const a=n.getFields(),s=[],l=[];for(const e of Object.keys(a).map((e=>a[e])))e.deprecationReason?l.push(e):s.push(e);return fe(pe,{children:[s.length>0?de(sT,{title:"Fields",children:s.map((e=>de(jw,{field:e},e.name)))}):null,l.length>0?i||0===s.length?de(sT,{title:"Deprecated Fields",children:l.map((e=>de(jw,{field:e},e.name)))}):de(as,{type:"button",onClick:()=>{o(!0)},children:"Show Deprecated Fields"}):null]})}function jw(e){let{field:t}=e;const n="args"in t?t.args.filter((e=>!e.deprecationReason)):[];return fe("div",{className:"graphiql-doc-explorer-item",children:[fe("div",{children:[de(Lw,{field:t}),n.length>0?fe(pe,{children:["(",de("span",{children:n.map((e=>1===n.length?de(JE,{arg:e,inline:!0},e.name):de("div",{className:"graphiql-doc-explorer-argument-multiple",children:de(JE,{arg:e,inline:!0})},e.name)))}),")"]}):null,": ",de(QE,{type:t.type}),de(IE,{field:t})]}),t.description?de(rb,{type:"description",onlyShowFirstChild:!0,children:t.description}):null,de(tT,{children:t.deprecationReason})]})}function Vw(e){let{type:n}=e;const[i,o]=(0,t.useState)(!1);if(!(0,r.isEnumType)(n))return null;const a=[],s=[];for(const e of n.getValues())e.deprecationReason?s.push(e):a.push(e);return fe(pe,{children:[a.length>0?de(sT,{title:"Enum Values",children:a.map((e=>de(Uw,{value:e},e.name)))}):null,s.length>0?i||0===a.length?de(sT,{title:"Deprecated Enum Values",children:s.map((e=>de(Uw,{value:e},e.name)))}):de(as,{type:"button",onClick:()=>{o(!0)},children:"Show Deprecated Values"}):null]})}function Uw(e){let{value:t}=e;return fe("div",{className:"graphiql-doc-explorer-item",children:[de("div",{className:"graphiql-doc-explorer-enum-value",children:t.name}),t.description?de(rb,{type:"description",children:t.description}):null,t.deprecationReason?de(rb,{type:"deprecation",children:t.deprecationReason}):null]})}function Bw(e){let{type:t}=e;const{schema:n}=RE({nonNull:!0});return n&&(0,r.isAbstractType)(t)?de(sT,{title:(0,r.isInterfaceType)(t)?"Implementations":"Possible Types",children:n.getPossibleTypes(t).map((e=>de("div",{children:de(QE,{type:e})},e.name)))}):null}g(Rw,"TypeDocumentation"),Mw(Rw,"TypeDocumentation"),g(Fw,"ImplementsInterfaces"),Mw(Fw,"ImplementsInterfaces"),g(Pw,"Fields"),Mw(Pw,"Fields"),g(jw,"Field"),Mw(jw,"Field"),g(Vw,"EnumValues"),Mw(Vw,"EnumValues"),g(Uw,"EnumValue"),Mw(Uw,"EnumValue"),g(Bw,"PossibleTypes"),Mw(Bw,"PossibleTypes");var $w=Object.defineProperty,qw=g(((e,t)=>$w(e,"name",{value:t,configurable:!0})),"__name$j");function Hw(){const{fetchError:e,isFetching:t,schema:n,validationErrors:i}=RE({nonNull:!0,caller:Hw}),{explorerNavStack:o,pop:a}=qE({nonNull:!0,caller:Hw}),s=o.at(-1);let l,u=null;return e?u=de("div",{className:"graphiql-doc-explorer-error",children:"Error fetching schema"}):i.length>0?u=fe("div",{className:"graphiql-doc-explorer-error",children:["Schema is invalid: ",i[0].message]}):t?u=de(ib,{}):n?1===o.length?u=de(gT,{schema:n}):(0,r.isType)(s.def)?u=de(Rw,{type:s.def}):s.def&&(u=de(dT,{field:s.def})):u=de("div",{className:"graphiql-doc-explorer-error",children:"No GraphQL schema available"}),o.length>1&&(l=o.at(-2).name),fe("section",{className:"graphiql-doc-explorer","aria-label":"Documentation Explorer",children:[fe("div",{className:"graphiql-doc-explorer-header",children:[fe("div",{className:"graphiql-doc-explorer-header-content",children:[l&&fe("a",{href:"#",className:"graphiql-doc-explorer-back",onClick:e=>{e.preventDefault(),a()},"aria-label":`Go back to ${l}`,children:[de(Ia,{}),l]}),de("div",{className:"graphiql-doc-explorer-title",children:s.name})]}),de("div",{className:"graphiql-doc-explorer-search",children:de(xw,{},s.name)})]}),de("div",{className:"graphiql-doc-explorer-content",children:u})]})}g(Hw,"DocExplorer"),qw(Hw,"DocExplorer");var Gw=Object.defineProperty,zw=g(((e,t)=>Gw(e,"name",{value:t,configurable:!0})),"__name$i");const Ww={title:"Documentation Explorer",icon:zw(g((function(){const e=Yw();return(null==e?void 0:e.visiblePlugin)===Ww?de(ja,{}):de(Va,{})}),"Icon"),"Icon"),content:Hw};e._=Ww;const Kw={title:"History",icon:$a,content:oE};e.$=Kw;const Qw=X("PluginContext");function Xw(e){const n=ye(),r=qE(),i=tE(),o=Boolean(r),a=Boolean(i),s=(0,t.useMemo)((()=>{const t=[],n={};o&&(t.push(Ww),n[Ww.title]=!0),a&&(t.push(Kw),n[Kw.title]=!0);for(const r of e.plugins||[]){if("string"!=typeof r.title||!r.title)throw new Error("All GraphiQL plugins must have a unique title");if(n[r.title])throw new Error(`All GraphiQL plugins must have a unique title, found two plugins with the title '${r.title}'`);t.push(r),n[r.title]=!0}return t}),[o,a,e.plugins]),[l,u]=(0,t.useState)((()=>{const t=null==n?void 0:n.get(Jw);return s.find((e=>e.title===t))||(t&&(null==n||n.set(Jw,"")),e.visiblePlugin&&s.find((t=>("string"==typeof e.visiblePlugin?t.title:t)===e.visiblePlugin))||null)})),{onTogglePluginVisibility:c,children:d}=e,f=(0,t.useCallback)((e=>{const t=e&&s.find((t=>("string"==typeof e?t.title:t)===e))||null;u((e=>t===e?e:(null==c||c(t),t)))}),[c,s]);(0,t.useEffect)((()=>{e.visiblePlugin&&f(e.visiblePlugin)}),[s,e.visiblePlugin,f]);const p=(0,t.useMemo)((()=>({plugins:s,setVisiblePlugin:f,visiblePlugin:l})),[s,f,l]);return de(Qw.Provider,{value:p,children:d})}e.a0=Qw,g(Xw,"PluginContextProvider"),zw(Xw,"PluginContextProvider");const Yw=Y(Qw);e.a2=Yw;const Jw="visiblePlugin";var Zw=Object.defineProperty,eC=g(((e,t)=>Zw(e,"name",{value:t,configurable:!0})),"__name$h");function tC(e,t,n,i,o,a){function s(e){if(!(n&&i&&o&&e.currentTarget instanceof HTMLElement))return;const t=e.currentTarget.innerText,r=n.getType(t);r&&(o.setVisiblePlugin(Ww),i.push({name:r.name,def:r}),null==a||a(r))}EE([],{useCommonAddons:!1}).then((e=>{let n,i,o,a,l,u,c,d,f;e.on(t,"select",((e,t)=>{if(!n){const e=t.parentNode;n=document.createElement("div"),n.className="CodeMirror-hint-information",e.append(n);const r=document.createElement("header");r.className="CodeMirror-hint-information-header",n.append(r),i=document.createElement("span"),i.className="CodeMirror-hint-information-field-name",r.append(i),o=document.createElement("span"),o.className="CodeMirror-hint-information-type-name-pill",r.append(o),a=document.createElement("span"),o.append(a),l=document.createElement("a"),l.className="CodeMirror-hint-information-type-name",l.href="javascript:void 0",l.addEventListener("click",s),o.append(l),u=document.createElement("span"),o.append(u),c=document.createElement("div"),c.className="CodeMirror-hint-information-description",n.append(c),d=document.createElement("div"),d.className="CodeMirror-hint-information-deprecation",n.append(d);const p=document.createElement("span");p.className="CodeMirror-hint-information-deprecation-label",p.innerText="Deprecated",d.append(p),f=document.createElement("div"),f.className="CodeMirror-hint-information-deprecation-reason",d.append(f);const h=parseInt(window.getComputedStyle(n).paddingBottom.replace(/px$/,""),10)||0,m=parseInt(window.getComputedStyle(n).maxHeight.replace(/px$/,""),10)||0,g=eC((()=>{n&&(n.style.paddingTop=e.scrollTop+h+"px",n.style.maxHeight=e.scrollTop+m+"px")}),"handleScroll");let v;e.addEventListener("scroll",g),e.addEventListener("DOMNodeRemoved",v=eC((t=>{t.target===e&&(e.removeEventListener("scroll",g),e.removeEventListener("DOMNodeRemoved",v),n&&n.removeEventListener("click",s),n=null,i=null,o=null,a=null,l=null,u=null,c=null,d=null,f=null,v=null)}),"onRemoveFn"))}if(i&&(i.innerText=e.text),o&&a&&l&&u)if(e.type){o.style.display="inline";const t=eC((e=>{(0,r.isNonNullType)(e)?(u.innerText="!"+u.innerText,t(e.ofType)):(0,r.isListType)(e)?(a.innerText+="[",u.innerText="]"+u.innerText,t(e.ofType)):l.innerText=e.name}),"renderType");a.innerText="",u.innerText="",t(e.type)}else a.innerText="",l.innerText="",u.innerText="",o.style.display="none";c&&(e.description?(c.style.display="block",c.innerHTML=nb.render(e.description)):(c.style.display="none",c.innerHTML="")),d&&f&&(e.deprecationReason?(d.style.display="block",f.innerHTML=nb.render(e.deprecationReason)):(d.style.display="none",f.innerHTML=""))}))})),g(s,"onClickHintInformation"),eC(s,"onClickHintInformation")}g(tC,"onHasCompletion"),eC(tC,"onHasCompletion");var nC=Object.defineProperty,rC=g(((e,t)=>nC(e,"name",{value:t,configurable:!0})),"__name$g");function iC(e,n){(0,t.useEffect)((()=>{e&&"string"==typeof n&&n!==e.getValue()&&e.setValue(n)}),[e,n])}function oC(e,n,r){(0,t.useEffect)((()=>{e&&e.setOption(n,r)}),[e,n,r])}function aC(e,n,r,i,o){const{updateActiveTabValues:a}=oS({nonNull:!0,caller:o}),s=ye();(0,t.useEffect)((()=>{if(!e)return;const t=ww(500,(e=>{s&&null!==r&&s.set(r,e)})),o=ww(100,(e=>{a({[i]:e})})),l=rC(((e,r)=>{if(!r)return;const i=e.getValue();t(i),o(i),null==n||n(i)}),"handleChange");return e.on("change",l),()=>e.off("change",l)}),[n,e,s,r,i,a])}function sC(e,n,r){const{schema:i}=RE({nonNull:!0,caller:r}),o=qE(),a=Yw();(0,t.useEffect)((()=>{if(!e)return;const t=rC(((e,t)=>{tC(0,t,i,o,a,(e=>{null==n||n({kind:"Type",type:e,schema:i||void 0})}))}),"handleCompletion");return e.on("hasCompletion",t),()=>e.off("hasCompletion",t)}),[n,e,o,a,i])}function lC(e,n,r){(0,t.useEffect)((()=>{if(e){for(const t of n)e.removeKeyMap(t);if(r){const t={};for(const e of n)t[e]=()=>r();e.addKeyMap(t)}}}),[e,n,r])}function uC(){let{caller:e,onCopyQuery:n}=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};const{queryEditor:r}=oS({nonNull:!0,caller:e||uC});return(0,t.useCallback)((()=>{if(!r)return;const e=r.getValue();kE(e),null==n||n(e)}),[r,n])}function cC(){let{caller:e}=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};const{queryEditor:n}=oS({nonNull:!0,caller:e||cC}),{schema:i}=RE({nonNull:!0,caller:cC});return(0,t.useCallback)((()=>{const e=null==n?void 0:n.documentAST,t=null==n?void 0:n.getValue();e&&t&&n.setValue((0,r.print)(B(e,i)))}),[n,i])}function dC(){let{caller:e}=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};const{queryEditor:n,headerEditor:i,variableEditor:o}=oS({nonNull:!0,caller:e||dC});return(0,t.useCallback)((()=>{if(o){const e=o.getValue();try{const t=JSON.stringify(JSON.parse(e),null,2);t!==e&&o.setValue(t)}catch{}}if(i){const e=i.getValue();try{const t=JSON.stringify(JSON.parse(e),null,2);t!==e&&i.setValue(t)}catch{}}if(n){const e=n.getValue(),t=(0,r.print)((0,r.parse)(e));t!==e&&n.setValue(t)}}),[n,o,i])}function fC(){let{getDefaultFieldNames:e,caller:n}=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};const{schema:r}=RE({nonNull:!0,caller:n||fC}),{queryEditor:i}=oS({nonNull:!0,caller:n||fC});return(0,t.useCallback)((()=>{if(!i)return;const t=i.getValue(),{insertions:n,result:o}=A(r,t,e);return n&&n.length>0&&i.operation((()=>{const e=i.getCursor(),t=i.indexFromPos(e);i.setValue(o||"");let r=0;const a=n.map((e=>{let{index:t,string:n}=e;return i.markText(i.posFromIndex(t+r),i.posFromIndex(t+(r+=n.length)),{className:"auto-inserted-leaf",clearOnEnter:!0,title:"Automatically added leaf fields"})}));setTimeout((()=>{for(const e of a)e.clear()}),7e3);let s=t;for(const{index:e,string:r}of n)epC(e,"name",{value:t,configurable:!0})),"__name$f");function mC(){let{editorTheme:e=gE,keyMap:r=vE,onEdit:i,readOnly:o=!1}=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},a=arguments.length>1?arguments[1]:void 0;const{initialHeaders:s,headerEditor:l,setHeaderEditor:u,shouldPersistHeaders:c}=oS({nonNull:!0,caller:a||mC}),d=fE(),f=cC({caller:a||mC}),p=dC({caller:a||mC}),h=(0,t.useRef)(null);return(0,t.useEffect)((()=>{let t=!0;return EE([Promise.resolve().then(n.t.bind(n,8888,23)).then((function(e){return e.j}))]).then((n=>{if(!t)return;const r=h.current;if(!r)return;const i=n(r,{value:s,lineNumbers:!0,tabSize:2,mode:{name:"javascript",json:!0},theme:e,autoCloseBrackets:!0,matchBrackets:!0,showCursorWhenSelecting:!0,readOnly:!!o&&"nocursor",foldGutter:!0,gutters:["CodeMirror-linenumbers","CodeMirror-foldgutter"],extraKeys:bE});i.addKeyMap({"Cmd-Space"(){i.showHint({completeSingle:!1,container:r})},"Ctrl-Space"(){i.showHint({completeSingle:!1,container:r})},"Alt-Space"(){i.showHint({completeSingle:!1,container:r})},"Shift-Space"(){i.showHint({completeSingle:!1,container:r})}}),i.on("keyup",((e,t)=>{const{keyCode:n,key:r,shiftKey:i}=t;(n>=65&&n<=90||!i&&n>=48&&n<=57||"_"===r||'"'===r)&&e.execCommand("autocomplete")})),u(i)})),()=>{t=!1}}),[e,s,o,u]),oC(l,"keyMap",r),aC(l,i,c?gC:null,"headers",mC),lC(l,["Cmd-Enter","Ctrl-Enter"],null==d?void 0:d.run),lC(l,["Shift-Ctrl-P"],p),lC(l,["Shift-Ctrl-M"],f),h}g(mC,"useHeaderEditor"),hC(mC,"useHeaderEditor");const gC="headers";var vC=Object.defineProperty,yC=g(((e,t)=>vC(e,"name",{value:t,configurable:!0})),"__name$e");const bC=Array.from({length:11},((e,t)=>String.fromCharCode(8192+t))).concat(["\u2028","\u2029"," "," "]),EC=new RegExp("["+bC.join("")+"]","g");function TC(e){return e.replace(EC," ")}g(TC,"normalizeWhitespace"),yC(TC,"normalizeWhitespace");var wC=Object.defineProperty,CC=g(((e,t)=>wC(e,"name",{value:t,configurable:!0})),"__name$d");function SC(){let{editorTheme:e=gE,keyMap:r=vE,onClickReference:i,onCopyQuery:o,onEdit:a,readOnly:s=!1}=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},l=arguments.length>1?arguments[1]:void 0;const{schema:u}=RE({nonNull:!0,caller:l||SC}),{externalFragments:c,initialQuery:d,queryEditor:f,setOperationName:p,setQueryEditor:v,validationRules:y,variableEditor:b,updateActiveTabValues:E}=oS({nonNull:!0,caller:l||SC}),T=fE(),w=ye(),C=qE(),S=Yw(),x=uC({caller:l||SC,onCopyQuery:o}),k=cC({caller:l||SC}),N=dC({caller:l||SC}),_=(0,t.useRef)(null),O=(0,t.useRef)(),I=(0,t.useRef)((()=>{}));(0,t.useEffect)((()=>{I.current=e=>{if(C&&S){switch(S.setVisiblePlugin(Ww),e.kind){case"Type":C.push({name:e.type.name,def:e.type});break;case"Field":C.push({name:e.field.name,def:e.field});break;case"Argument":e.field&&C.push({name:e.field.name,def:e.field});break;case"EnumValue":e.type&&C.push({name:e.type.name,def:e.type})}null==i||i(e)}}}),[C,i,S]),(0,t.useEffect)((()=>{let t=!0;return EE([Promise.resolve().then(n.t.bind(n,6754,23)).then((function(e){return e.c})),Promise.resolve().then(n.t.bind(n,9509,23)).then((function(e){return e.s})),Promise.resolve().then(n.t.bind(n,4840,23)),Promise.resolve().then(n.t.bind(n,9444,23)),Promise.resolve().then(n.t.bind(n,9890,23)),Promise.resolve().then(n.t.bind(n,5980,23)),Promise.resolve().then(n.t.bind(n,9863,23))]).then((n=>{if(!t)return;O.current=n;const r=_.current;if(!r)return;const i=n(r,{value:d,lineNumbers:!0,tabSize:2,foldGutter:!0,mode:"graphql",theme:e,autoCloseBrackets:!0,matchBrackets:!0,showCursorWhenSelecting:!0,readOnly:!!s&&"nocursor",lint:{schema:void 0,validationRules:null,externalFragments:void 0},hintOptions:{schema:void 0,closeOnUnfocus:!1,completeSingle:!1,container:r,externalFragments:void 0},info:{schema:void 0,renderDescription:e=>nb.render(e),onClick:e=>{I.current(e)}},jump:{schema:void 0,onClick:e=>{I.current(e)}},gutters:["CodeMirror-linenumbers","CodeMirror-foldgutter"],extraKeys:m(h({},bE),{"Cmd-S"(){},"Ctrl-S"(){}})});i.addKeyMap({"Cmd-Space"(){i.showHint({completeSingle:!0,container:r})},"Ctrl-Space"(){i.showHint({completeSingle:!0,container:r})},"Alt-Space"(){i.showHint({completeSingle:!0,container:r})},"Shift-Space"(){i.showHint({completeSingle:!0,container:r})},"Shift-Alt-Space"(){i.showHint({completeSingle:!0,container:r})}}),i.on("keyup",((e,t)=>{_C.test(t.key)&&e.execCommand("autocomplete")}));let o=!1;i.on("startCompletion",(()=>{o=!0})),i.on("endCompletion",(()=>{o=!1})),i.on("keydown",((e,t)=>{"Escape"===t.key&&o&&t.stopPropagation()})),i.on("beforeChange",((e,t)=>{var n;if("paste"===t.origin){const e=t.text.map(TC);null==(n=t.update)||n.call(t,t.from,t.to,e)}})),i.documentAST=null,i.operationName=null,i.operations=null,i.variableToType=null,v(i)})),()=>{t=!1}}),[e,d,s,v]),oC(f,"keyMap",r),(0,t.useEffect)((()=>{if(!f)return;function e(e){var t,n,r,i,o;const a=Do(u,e.getValue()),s=$(null!=(t=e.operations)?t:void 0,null!=(n=e.operationName)?n:void 0,null==a?void 0:a.operations);return e.documentAST=null!=(r=null==a?void 0:a.documentAST)?r:null,e.operationName=null!=s?s:null,e.operations=null!=(i=null==a?void 0:a.operations)?i:null,b&&(b.state.lint.linterOptions.variableToType=null==a?void 0:a.variableToType,b.options.lint.variableToType=null==a?void 0:a.variableToType,b.options.hintOptions.variableToType=null==a?void 0:a.variableToType,null==(o=O.current)||o.signal(b,"change",b)),a?m(h({},a),{operationName:s}):null}g(e,"getAndUpdateOperationFacts"),CC(e,"getAndUpdateOperationFacts");const t=ww(100,(t=>{var n;const r=t.getValue();null==w||w.set(OC,r);const i=t.operationName,o=e(t);void 0!==(null==o?void 0:o.operationName)&&(null==w||w.set(IC,o.operationName)),null==a||a(r,null==o?void 0:o.documentAST),(null==o?void 0:o.operationName)&&i!==o.operationName&&p(o.operationName),E({query:r,operationName:null!=(n=null==o?void 0:o.operationName)?n:null})}));return e(f),f.on("change",t),()=>f.off("change",t)}),[a,f,u,p,w,b,E]),xC(f,null!=u?u:null,O),kC(f,null!=y?y:null,O),NC(f,c,O),sC(f,i||null,SC);const D=null==T?void 0:T.run,L=(0,t.useCallback)((()=>{var e;if(!(D&&f&&f.operations&&f.hasFocus()))return void(null==D||D());const t=f.indexFromPos(f.getCursor());let n;for(const r of f.operations)r.loc&&r.loc.start<=t&&r.loc.end>=t&&(n=null==(e=r.name)?void 0:e.value);n&&n!==f.operationName&&p(n),D()}),[f,D,p]);return lC(f,["Cmd-Enter","Ctrl-Enter"],L),lC(f,["Shift-Ctrl-C"],x),lC(f,["Shift-Ctrl-P","Shift-Ctrl-F"],N),lC(f,["Shift-Ctrl-M"],k),_}function xC(e,n,r){(0,t.useEffect)((()=>{if(!e)return;const t=e.options.lint.schema!==n;e.state.lint.linterOptions.schema=n,e.options.lint.schema=n,e.options.hintOptions.schema=n,e.options.info.schema=n,e.options.jump.schema=n,t&&r.current&&r.current.signal(e,"change",e)}),[e,n,r])}function kC(e,n,r){(0,t.useEffect)((()=>{if(!e)return;const t=e.options.lint.validationRules!==n;e.state.lint.linterOptions.validationRules=n,e.options.lint.validationRules=n,t&&r.current&&r.current.signal(e,"change",e)}),[e,n,r])}function NC(e,n,r){const i=(0,t.useMemo)((()=>[...n.values()]),[n]);(0,t.useEffect)((()=>{if(!e)return;const t=e.options.lint.externalFragments!==i;e.state.lint.linterOptions.externalFragments=i,e.options.lint.externalFragments=i,e.options.hintOptions.externalFragments=i,t&&r.current&&r.current.signal(e,"change",e)}),[e,i,r])}g(SC,"useQueryEditor"),CC(SC,"useQueryEditor"),g(xC,"useSynchronizeSchema"),CC(xC,"useSynchronizeSchema"),g(kC,"useSynchronizeValidationRules"),CC(kC,"useSynchronizeValidationRules"),g(NC,"useSynchronizeExternalFragments"),CC(NC,"useSynchronizeExternalFragments");const _C=/^[a-zA-Z0-9_@(]$/,OC="query",IC="operationName";var DC=Object.defineProperty,LC=g(((e,t)=>DC(e,"name",{value:t,configurable:!0})),"__name$c");function AC(e){let{defaultQuery:t,defaultHeaders:n,headers:r,defaultTabs:i,query:o,variables:a,storage:s}=e;const l=null==s?void 0:s.get(XC);try{if(!l)throw new Error("Storage for tabs is empty");const e=JSON.parse(l);if(MC(e)){const t=zC({query:o,variables:a,headers:r});let n=-1;for(let r=0;r=0)e.activeTabIndex=n;else{const n=o?WC(o):null;e.tabs.push({id:GC(),hash:t,title:n||QC,query:o,variables:a,headers:r,operationName:n,response:null}),e.activeTabIndex=e.tabs.length-1}return e}throw new Error("Storage for tabs is invalid")}catch{return{activeTabIndex:0,tabs:(i||[{query:null!=o?o:t,variables:a,headers:null!=r?r:n}]).map(qC)}}}function MC(e){return e&&"object"==typeof e&&!Array.isArray(e)&&FC(e,"activeTabIndex")&&"tabs"in e&&Array.isArray(e.tabs)&&e.tabs.every(RC)}function RC(e){return e&&"object"==typeof e&&!Array.isArray(e)&&PC(e,"id")&&PC(e,"title")&&jC(e,"query")&&jC(e,"variables")&&jC(e,"headers")&&jC(e,"operationName")&&jC(e,"response")}function FC(e,t){return t in e&&"number"==typeof e[t]}function PC(e,t){return t in e&&"string"==typeof e[t]}function jC(e,t){return t in e&&("string"==typeof e[t]||null===e[t])}function VC(e){let{queryEditor:n,variableEditor:r,headerEditor:i,responseEditor:o}=e;return(0,t.useCallback)((e=>{var t,a,s,l,u;const c=null!=(t=null==n?void 0:n.getValue())?t:null,d=null!=(a=null==r?void 0:r.getValue())?a:null,f=null!=(s=null==i?void 0:i.getValue())?s:null,p=null!=(l=null==n?void 0:n.operationName)?l:null;return HC(e,{query:c,variables:d,headers:f,response:null!=(u=null==o?void 0:o.getValue())?u:null,operationName:p})}),[n,r,i,o])}function UC(e){let t=arguments.length>1&&void 0!==arguments[1]&&arguments[1];return JSON.stringify(e,((e,n)=>"hash"===e||"response"===e||!t&&"headers"===e?null:n))}function BC(e){let{storage:n,shouldPersistHeaders:r}=e;const i=(0,t.useMemo)((()=>ww(500,(e=>{null==n||n.set(XC,e)}))),[n]);return(0,t.useCallback)((e=>{i(UC(e,r))}),[r,i])}function $C(e){let{queryEditor:n,variableEditor:r,headerEditor:i,responseEditor:o}=e;return(0,t.useCallback)((e=>{let{query:t,variables:a,headers:s,response:l}=e;null==n||n.setValue(null!=t?t:""),null==r||r.setValue(null!=a?a:""),null==i||i.setValue(null!=s?s:""),null==o||o.setValue(null!=l?l:"")}),[i,n,o,r])}function qC(){let{query:e=null,variables:t=null,headers:n=null}=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return{id:GC(),hash:zC({query:e,variables:t,headers:n}),title:e&&WC(e)||QC,query:e,variables:t,headers:n,operationName:null,response:null}}function HC(e,t){return m(h({},e),{tabs:e.tabs.map(((n,r)=>{if(r!==e.activeTabIndex)return n;const i=h(h({},n),t);return m(h({},i),{hash:zC(i),title:i.operationName||(i.query?WC(i.query):void 0)||QC})}))})}function GC(){const e=LC((()=>Math.floor(65536*(1+Math.random())).toString(16).slice(1)),"s4");return`${e()}${e()}-${e()}-${e()}-${e()}-${e()}${e()}${e()}`}function zC(e){var t,n,r;return[null!=(t=e.query)?t:"",null!=(n=e.variables)?n:"",null!=(r=e.headers)?r:""].join("|")}function WC(e){var t;const n=/^(?!#).*(query|subscription|mutation)\s+([a-zA-Z0-9_]+)/m.exec(e);return null!=(t=null==n?void 0:n[2])?t:null}function KC(e){const t=null==e?void 0:e.get(XC);if(t){const n=JSON.parse(t);null==e||e.set(XC,JSON.stringify(n,((e,t)=>"headers"===e?null:t)))}}g(AC,"getDefaultTabState"),LC(AC,"getDefaultTabState"),g(MC,"isTabsState"),LC(MC,"isTabsState"),g(RC,"isTabState"),LC(RC,"isTabState"),g(FC,"hasNumberKey"),LC(FC,"hasNumberKey"),g(PC,"hasStringKey"),LC(PC,"hasStringKey"),g(jC,"hasStringOrNullKey"),LC(jC,"hasStringOrNullKey"),g(VC,"useSynchronizeActiveTabValues"),LC(VC,"useSynchronizeActiveTabValues"),g(UC,"serializeTabState"),LC(UC,"serializeTabState"),g(BC,"useStoreTabs"),LC(BC,"useStoreTabs"),g($C,"useSetEditorValues"),LC($C,"useSetEditorValues"),g(qC,"createTab"),LC(qC,"createTab"),g(HC,"setPropertiesInActiveTab"),LC(HC,"setPropertiesInActiveTab"),g(GC,"guid"),LC(GC,"guid"),g(zC,"hashFromTabContents"),LC(zC,"hashFromTabContents"),g(WC,"fuzzyExtractOperationName"),LC(WC,"fuzzyExtractOperationName"),g(KC,"clearHeadersFromTabs"),LC(KC,"clearHeadersFromTabs");const QC="",XC="tabState";var YC=Object.defineProperty,JC=g(((e,t)=>YC(e,"name",{value:t,configurable:!0})),"__name$b");function ZC(){let{editorTheme:e=gE,keyMap:r=vE,onClickReference:i,onEdit:o,readOnly:a=!1}=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},s=arguments.length>1?arguments[1]:void 0;const{initialVariables:l,variableEditor:u,setVariableEditor:c}=oS({nonNull:!0,caller:s||ZC}),d=fE(),f=cC({caller:s||ZC}),p=dC({caller:s||ZC}),h=(0,t.useRef)(null),m=(0,t.useRef)();return(0,t.useEffect)((()=>{let t=!0;return EE([Promise.resolve().then(n.t.bind(n,4712,23)),Promise.resolve().then(n.t.bind(n,8535,23)),Promise.resolve().then(n.t.bind(n,3340,23))]).then((n=>{if(!t)return;m.current=n;const r=h.current;if(!r)return;const i=n(r,{value:l,lineNumbers:!0,tabSize:2,mode:"graphql-variables",theme:e,autoCloseBrackets:!0,matchBrackets:!0,showCursorWhenSelecting:!0,readOnly:!!a&&"nocursor",foldGutter:!0,lint:{variableToType:void 0},hintOptions:{closeOnUnfocus:!1,completeSingle:!1,container:r,variableToType:void 0},gutters:["CodeMirror-linenumbers","CodeMirror-foldgutter"],extraKeys:bE});i.addKeyMap({"Cmd-Space"(){i.showHint({completeSingle:!1,container:r})},"Ctrl-Space"(){i.showHint({completeSingle:!1,container:r})},"Alt-Space"(){i.showHint({completeSingle:!1,container:r})},"Shift-Space"(){i.showHint({completeSingle:!1,container:r})}}),i.on("keyup",((e,t)=>{const{keyCode:n,key:r,shiftKey:i}=t;(n>=65&&n<=90||!i&&n>=48&&n<=57||"_"===r||'"'===r)&&e.execCommand("autocomplete")})),c(i)})),()=>{t=!1}}),[e,l,a,c]),oC(u,"keyMap",r),aC(u,o,eS,"variables",ZC),sC(u,i||null,ZC),lC(u,["Cmd-Enter","Ctrl-Enter"],null==d?void 0:d.run),lC(u,["Shift-Ctrl-P"],p),lC(u,["Shift-Ctrl-M"],f),h}g(ZC,"useVariableEditor"),JC(ZC,"useVariableEditor");const eS="variables";var tS=Object.defineProperty,nS=g(((e,t)=>tS(e,"name",{value:t,configurable:!0})),"__name$a");const rS=X("EditorContext");function iS(e){const n=ye(),[i,o]=(0,t.useState)(null),[a,s]=(0,t.useState)(null),[l,u]=(0,t.useState)(null),[c,d]=(0,t.useState)(null),[f,p]=(0,t.useState)((()=>{const t=null!==(null==n?void 0:n.get(aS));return!1!==e.shouldPersistHeaders&&t?"true"===(null==n?void 0:n.get(aS)):Boolean(e.shouldPersistHeaders)}));iC(i,e.headers),iC(a,e.query),iC(l,e.response),iC(c,e.variables);const g=BC({storage:n,shouldPersistHeaders:f}),[v]=(0,t.useState)((()=>{var t,r,i,o,a,s,l,u,c;const d=null!=(r=null!=(t=e.query)?t:null==n?void 0:n.get(OC))?r:null,f=null!=(o=null!=(i=e.variables)?i:null==n?void 0:n.get(eS))?o:null,p=null!=(s=null!=(a=e.headers)?a:null==n?void 0:n.get(gC))?s:null,h=null!=(l=e.response)?l:"",m=AC({query:d,variables:f,headers:p,defaultTabs:e.defaultTabs||e.initialTabs,defaultQuery:e.defaultQuery||sS,defaultHeaders:e.defaultHeaders,storage:n});return g(m),{query:null!=(u=null!=d?d:0===m.activeTabIndex?m.tabs[0].query:null)?u:"",variables:null!=f?f:"",headers:null!=(c=null!=p?p:e.defaultHeaders)?c:"",response:h,tabState:m}})),[y,b]=(0,t.useState)(v.tabState),E=(0,t.useCallback)((e=>{var t;if(e){null==n||n.set(gC,null!=(t=null==i?void 0:i.getValue())?t:"");const e=UC(y,!0);null==n||n.set(XC,e)}else null==n||n.set(gC,""),KC(n);p(e),null==n||n.set(aS,e.toString())}),[n,y,i]),T=(0,t.useRef)();(0,t.useEffect)((()=>{const t=Boolean(e.shouldPersistHeaders);T.current!==t&&(E(t),T.current=t)}),[e.shouldPersistHeaders,E]);const w=VC({queryEditor:a,variableEditor:c,headerEditor:i,responseEditor:l}),C=$C({queryEditor:a,variableEditor:c,headerEditor:i,responseEditor:l}),{onTabChange:S,defaultHeaders:x,children:k}=e,N=(0,t.useCallback)((()=>{b((e=>{const t=w(e),n={tabs:[...t.tabs,qC({headers:x})],activeTabIndex:t.tabs.length};return g(n),C(n.tabs[n.activeTabIndex]),null==S||S(n),n}))}),[x,S,C,g,w]),_=(0,t.useCallback)((e=>{b((t=>{const n=m(h({},w(t)),{activeTabIndex:e});return g(n),C(n.tabs[n.activeTabIndex]),null==S||S(n),n}))}),[S,C,g,w]),O=(0,t.useCallback)((e=>{b((t=>{const n={tabs:t.tabs.filter(((t,n)=>e!==n)),activeTabIndex:Math.max(t.activeTabIndex-1,0)};return g(n),C(n.tabs[n.activeTabIndex]),null==S||S(n),n}))}),[S,C,g]),I=(0,t.useCallback)((e=>{b((t=>{const n=HC(t,e);return g(n),null==S||S(n),n}))}),[S,g]),{onEditOperationName:D}=e,L=(0,t.useCallback)((e=>{a&&(a.operationName=e,I({operationName:e}),null==D||D(e))}),[D,a,I]),A=(0,t.useMemo)((()=>{const t=new Map;if(Array.isArray(e.externalFragments))for(const n of e.externalFragments)t.set(n.name.value,n);else if("string"==typeof e.externalFragments)(0,r.visit)((0,r.parse)(e.externalFragments,{}),{FragmentDefinition(e){t.set(e.name.value,e)}});else if(e.externalFragments)throw new Error("The `externalFragments` prop must either be a string that contains the fragment definitions in SDL or a list of FragmentDefinitionNode objects.");return t}),[e.externalFragments]),M=(0,t.useMemo)((()=>e.validationRules||[]),[e.validationRules]),R=(0,t.useMemo)((()=>m(h({},y),{addTab:N,changeTab:_,closeTab:O,updateActiveTabValues:I,headerEditor:i,queryEditor:a,responseEditor:l,variableEditor:c,setHeaderEditor:o,setQueryEditor:s,setResponseEditor:u,setVariableEditor:d,setOperationName:L,initialQuery:v.query,initialVariables:v.variables,initialHeaders:v.headers,initialResponse:v.response,externalFragments:A,validationRules:M,shouldPersistHeaders:f,setShouldPersistHeaders:E})),[y,N,_,O,I,i,a,l,c,L,v,A,M,f,E]);return de(rS.Provider,{value:R,children:k})}e.E=rS,g(iS,"EditorContextProvider"),nS(iS,"EditorContextProvider");const oS=Y(rS);e.f=oS;const aS="shouldPersistHeaders",sS='# Welcome to GraphiQL\n#\n# GraphiQL is an in-browser tool for writing, validating, and\n# testing GraphQL queries.\n#\n# Type queries into this side of the screen, and you will see intelligent\n# typeaheads aware of the current GraphQL type schema and live syntax and\n# validation errors highlighted within the text.\n#\n# GraphQL queries typically start with a "{" character. Lines that start\n# with a # are ignored.\n#\n# An example GraphQL query might look like:\n#\n# {\n# field(arg: "value") {\n# subField\n# }\n# }\n#\n# Keyboard shortcuts:\n#\n# Prettify query: Shift-Ctrl-P (or press the prettify button)\n#\n# Merge fragments: Shift-Ctrl-M (or press the merge button)\n#\n# Run Query: Ctrl-Enter (or press the play button)\n#\n# Auto Complete: Ctrl-Space (or just start typing)\n#\n\n';var lS=Object.defineProperty,uS=g(((e,t)=>lS(e,"name",{value:t,configurable:!0})),"__name$9");function cS(e){var n=e,{isHidden:r}=n,i=v(n,["isHidden"]);const{headerEditor:o}=oS({nonNull:!0,caller:cS}),a=mC(i,cS);return(0,t.useEffect)((()=>{o&&!r&&o.refresh()}),[o,r]),de("div",{className:b("graphiql-editor",r&&"hidden"),ref:a})}g(cS,"HeaderEditor"),uS(cS,"HeaderEditor");var dS=Object.defineProperty,fS=g(((e,t)=>dS(e,"name",{value:t,configurable:!0})),"__name$8");function pS(e){var n;const[r,i]=(0,t.useState)({width:null,height:null}),[o,a]=(0,t.useState)(null),s=(0,t.useRef)(null),l=null==(n=hS(e.token))?void 0:n.href;(0,t.useEffect)((()=>{if(s.current)return l?void fetch(l,{method:"HEAD"}).then((e=>{a(e.headers.get("Content-Type"))})).catch((()=>{a(null)})):(i({width:null,height:null}),void a(null))}),[l]);const u=null!==r.width&&null!==r.height?fe("div",{children:[r.width,"x",r.height,null===o?null:" "+o]}):null;return fe("div",{children:[de("img",{onLoad:()=>{var e,t,n,r;i({width:null!=(t=null==(e=s.current)?void 0:e.naturalWidth)?t:null,height:null!=(r=null==(n=s.current)?void 0:n.naturalHeight)?r:null})},ref:s,src:l}),u]})}function hS(e){if("string"!==e.type)return;const t=e.string.slice(1).slice(0,-1).trim();try{const{location:e}=window;return new URL(t,e.protocol+"//"+e.host)}catch{return}}function mS(e){return/(bmp|gif|jpeg|jpg|png|svg)$/.test(e.pathname)}g(pS,"ImagePreview"),fS(pS,"ImagePreview"),pS.shouldRender=fS(g((function(e){const t=hS(e);return!!t&&mS(t)}),"shouldRender"),"shouldRender"),g(hS,"tokenToURL"),fS(hS,"tokenToURL"),g(mS,"isImageURL"),fS(mS,"isImageURL");var gS=Object.defineProperty,vS=g(((e,t)=>gS(e,"name",{value:t,configurable:!0})),"__name$7");function yS(e){const t=SC(e,yS);return de("div",{className:"graphiql-editor",ref:t})}g(yS,"QueryEditor"),vS(yS,"QueryEditor");var bS=Object.defineProperty,ES=g(((e,t)=>bS(e,"name",{value:t,configurable:!0})),"__name$6");function TS(){let{responseTooltip:e,editorTheme:r=gE,keyMap:o=vE}=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},a=arguments.length>1?arguments[1]:void 0;const{fetchError:s,validationErrors:l}=RE({nonNull:!0,caller:a||TS}),{initialResponse:u,responseEditor:c,setResponseEditor:d}=oS({nonNull:!0,caller:a||TS}),f=(0,t.useRef)(null),p=(0,t.useRef)(e);return(0,t.useEffect)((()=>{p.current=e}),[e]),(0,t.useEffect)((()=>{let e=!0;return EE([Promise.resolve().then(n.t.bind(n,8419,23)).then((function(e){return e.f})),Promise.resolve().then(n.t.bind(n,4468,23)).then((function(e){return e.b})),Promise.resolve().then(n.t.bind(n,8058,23)).then((function(e){return e.d})),Promise.resolve().then(n.t.bind(n,9509,23)).then((function(e){return e.s})),Promise.resolve().then(n.t.bind(n,9407,23)).then((function(e){return e.s})),Promise.resolve().then(n.t.bind(n,4471,23)).then((function(e){return e.j})),Promise.resolve().then(n.t.bind(n,2568,23)).then((function(e){return e.s})),Promise.resolve().then(n.t.bind(n,1430,23)),Promise.resolve().then(n.t.bind(n,7421,23))],{useCommonAddons:!1}).then((t=>{if(!e)return;const n=document.createElement("div");t.registerHelper("info","graphql-results",((e,t,r,o)=>{const a=[],s=p.current;return s&&a.push(de(s,{pos:o,token:e})),pS.shouldRender(e)&&a.push(de(pS,{token:e},"image-preview")),a.length?(i.default.render(a,n),n):(i.default.unmountComponentAtNode(n),null)}));const o=f.current;if(!o)return;const a=t(o,{value:u,lineWrapping:!0,readOnly:!0,theme:r,mode:"graphql-results",foldGutter:!0,gutters:["CodeMirror-foldgutter"],info:!0,extraKeys:bE});d(a)})),()=>{e=!1}}),[r,u,d]),oC(c,"keyMap",o),(0,t.useEffect)((()=>{s&&(null==c||c.setValue(s)),l.length>0&&(null==c||c.setValue(D(l)))}),[c,s,l]),f}g(TS,"useResponseEditor"),ES(TS,"useResponseEditor");var wS=Object.defineProperty,CS=g(((e,t)=>wS(e,"name",{value:t,configurable:!0})),"__name$5");function SS(e){const t=TS(e,SS);return de("section",{className:"result-window","aria-label":"Result Window","aria-live":"polite","aria-atomic":"true",ref:t})}g(SS,"ResponseEditor"),CS(SS,"ResponseEditor");var xS=Object.defineProperty,kS=g(((e,t)=>xS(e,"name",{value:t,configurable:!0})),"__name$4");function NS(e){var n=e,{isHidden:r}=n,i=v(n,["isHidden"]);const{variableEditor:o}=oS({nonNull:!0,caller:NS}),a=ZC(i,NS);return(0,t.useEffect)((()=>{o&&!r&&o.refresh()}),[o,r]),de("div",{className:b("graphiql-editor",r&&"hidden"),ref:a})}g(NS,"VariableEditor"),kS(NS,"VariableEditor");var _S=Object.defineProperty,OS=g(((e,t)=>_S(e,"name",{value:t,configurable:!0})),"__name$3");function IS(e){let{children:t,dangerouslyAssumeSchemaIsValid:n,defaultQuery:r,defaultHeaders:i,defaultTabs:o,externalFragments:a,fetcher:s,getDefaultFieldNames:l,headers:u,initialTabs:c,inputValueDeprecation:d,introspectionQueryName:f,maxHistoryLength:p,onEditOperationName:h,onSchemaChange:m,onTabChange:g,onTogglePluginVisibility:v,operationName:y,plugins:b,query:E,response:T,schema:w,schemaDescription:C,shouldPersistHeaders:S,storage:x,validationRules:k,variables:N,visiblePlugin:_}=e;return de(ve,{storage:x,children:de(eE,{maxHistoryLength:p,children:de(iS,{defaultQuery:r,defaultHeaders:i,defaultTabs:o,externalFragments:a,headers:u,initialTabs:c,onEditOperationName:h,onTabChange:g,query:E,response:T,shouldPersistHeaders:S,validationRules:k,variables:N,children:de(ME,{dangerouslyAssumeSchemaIsValid:n,fetcher:s,inputValueDeprecation:d,introspectionQueryName:f,onSchemaChange:m,schema:w,schemaDescription:C,children:de(dE,{getDefaultFieldNames:l,fetcher:s,operationName:y,children:de($E,{children:de(Xw,{onTogglePluginVisibility:v,plugins:b,visiblePlugin:_,children:t})})})})})})})}g(IS,"GraphiQLProvider"),OS(IS,"GraphiQLProvider");var DS=Object.defineProperty,LS=g(((e,t)=>DS(e,"name",{value:t,configurable:!0})),"__name$2");function AS(){const e=ye(),[n,r]=(0,t.useState)((()=>{if(!e)return null;const t=e.get(MS);switch(t){case"light":return"light";case"dark":return"dark";default:return"string"==typeof t&&e.set(MS,""),null}}));(0,t.useLayoutEffect)((()=>{"undefined"!=typeof window&&(document.body.classList.remove("graphiql-light","graphiql-dark"),n&&document.body.classList.add(`graphiql-${n}`))}),[n]);const i=(0,t.useCallback)((t=>{null==e||e.set(MS,t||""),r(t)}),[e]);return(0,t.useMemo)((()=>({theme:n,setTheme:i})),[n,i])}g(AS,"useTheme"),LS(AS,"useTheme");const MS="theme";var RS=Object.defineProperty,FS=g(((e,t)=>RS(e,"name",{value:t,configurable:!0})),"__name$1");function PS(e){let{defaultSizeRelation:n=jS,direction:r,initiallyHidden:i,onHiddenElementChange:o,sizeThresholdFirst:a=100,sizeThresholdSecond:s=100,storageKey:l}=e;const u=ye(),c=(0,t.useMemo)((()=>ww(500,(e=>{u&&l&&u.set(l,e)}))),[u,l]),[d,f]=(0,t.useState)((()=>{const e=u&&l?u.get(l):null;return e===VS||"first"===i?"first":e===US||"second"===i?"second":null})),p=(0,t.useCallback)((e=>{e!==d&&(f(e),null==o||o(e))}),[d,o]),h=(0,t.useRef)(null),m=(0,t.useRef)(null),v=(0,t.useRef)(null),y=(0,t.useRef)(`${n}`);(0,t.useLayoutEffect)((()=>{const e=u&&l&&u.get(l)||y.current,t="horizontal"===r?"row":"column";h.current&&(h.current.style.display="flex",h.current.style.flexDirection=t,h.current.style.flex=e===VS||e===US?y.current:e),v.current&&(v.current.style.display="flex",v.current.style.flexDirection=t,v.current.style.flex="1"),m.current&&(m.current.style.display="flex",m.current.style.flexDirection=t)}),[r,u,l]);const b=(0,t.useCallback)((e=>{const t="first"===e?h.current:v.current;if(t&&(t.style.left="-1000px",t.style.position="absolute",t.style.opacity="0",t.style.height="500px",t.style.width="500px",h.current)){const e=parseFloat(h.current.style.flex);(!Number.isFinite(e)||e<1)&&(h.current.style.flex="1")}}),[]),E=(0,t.useCallback)((e=>{const t="first"===e?h.current:v.current;if(t&&(t.style.width="",t.style.height="",t.style.opacity="",t.style.position="",t.style.left="",h.current&&u&&l)){const e=null==u?void 0:u.get(l);e!==VS&&e!==US&&(h.current.style.flex=e||y.current)}}),[u,l]);return(0,t.useLayoutEffect)((()=>{"first"===d?b("first"):E("first"),"second"===d?b("second"):E("second")}),[d,b,E]),(0,t.useEffect)((()=>{if(!m.current||!h.current||!v.current)return;const e=m.current,t=h.current,n=t.parentElement,i="horizontal"===r?"clientX":"clientY",o="horizontal"===r?"left":"top",l="horizontal"===r?"right":"bottom",u="horizontal"===r?"clientWidth":"clientHeight";function d(r){r.preventDefault();const d=r[i]-e.getBoundingClientRect()[o];function f(r){if(0===r.buttons)return h();const f=r[i]-n.getBoundingClientRect()[o]-d,m=n.getBoundingClientRect()[l]-r[i]+d-e[u];if(f{e.removeEventListener("mousedown",d),e.removeEventListener("dblclick",f)}}),[r,p,a,s,c]),(0,t.useMemo)((()=>({dragBarRef:m,hiddenElement:d,firstRef:h,setHiddenElement:f,secondRef:v})),[d,f])}g(PS,"useDragResize"),FS(PS,"useDragResize");const jS=1,VS="hide-first",US="hide-second",BS=(0,t.forwardRef)(((e,n)=>{var r=e,{label:i}=r,o=v(r,["label"]);const[a,s]=(0,t.useState)(null);return de(Pb,{label:i,children:de(os,m(h({},o),{ref:n,type:"button",className:b("graphiql-toolbar-button",a&&"error",o.className),onClick:e=>{var t;try{null==(t=o.onClick)||t.call(o,e),s(null)}catch(e){s(e instanceof Error?e:new Error(`Toolbar button click failed: ${e}`))}},"aria-label":a?a.message:i,"aria-invalid":a?"true":o["aria-invalid"]}))})}));e.aR=BS,BS.displayName="ToolbarButton";var $S=Object.defineProperty,qS=g(((e,t)=>$S(e,"name",{value:t,configurable:!0})),"__name");function HS(){const{queryEditor:e,setOperationName:t}=oS({nonNull:!0,caller:HS}),{isFetching:n,isSubscribed:r,operationName:i,run:o,stop:a}=fE({nonNull:!0,caller:HS}),s=(null==e?void 0:e.operations)||[],l=s.length>1&&"string"!=typeof i,u=n||r,c=(u?"Stop":"Execute")+" query (Ctrl-Enter)",d={type:"button",className:"graphiql-execute-button",children:de(u?ns:Ka,{}),"aria-label":c};return l&&!u?fe(Hh,{children:[de(Pb,{label:c,children:de(Hh.Button,h({},d))}),de(Hh.List,{children:s.map(((n,r)=>{const i=n.name?n.name.value:``;return de(Hh.Item,{onSelect:()=>{var r;const i=null==(r=n.name)?void 0:r.value;e&&i&&i!==e.operationName&&t(i),o()},children:i},`${i}-${r}`)}))})]}):de(Pb,{label:c,children:de("button",m(h({},d),{onClick:()=>{u?a():o()}}))})}g(HS,"ExecuteButton"),qS(HS,"ExecuteButton");const GS=(0,t.forwardRef)(((e,t)=>{var n=e,{button:r,children:i,label:o}=n,a=v(n,["button","children","label"]);const s=`${o}${a.value?`: ${a.value}`:""}`;return fe(zh.Input,m(h({},a),{ref:t,className:b("graphiql-toolbar-listbox",a.className),"aria-label":s,children:[de(Pb,{label:s,children:de(zh.Button,{children:r})}),de(zh.Popover,{children:i})]}))}));GS.displayName="ToolbarListbox";const zS=Xc(GS,{Option:zh.Option});e.aT=zS;const WS=(0,t.forwardRef)(((e,t)=>{var n=e,{button:r,children:i,label:o}=n,a=v(n,["button","children","label"]);return fe(Hh,m(h({},a),{ref:t,children:[de(Pb,{label:o,children:de(Hh.Button,{className:b("graphiql-un-styled graphiql-toolbar-menu",a.className),"aria-label":o,children:r})}),de(Hh.List,{children:i})]}))}));WS.displayName="ToolbarMenu";const KS=Xc(WS,{Item:Hh.Item});e.aU=KS},void 0===(o=r.apply(t,i))||(e.exports=o)},7421:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[n(535),n(6856),n(9196),n(3573),n(1850)],void 0===(o="function"==typeof(r=function(e,t,n,r,i){"use strict";var o=Object.defineProperty,a=(e,t)=>o(e,"name",{value:t,configurable:!0});function s(e){return{options:e instanceof Function?{render:e}:!0===e?{}:e}}function l(e){const{options:t}=e.state.info;return(null==t?void 0:t.hoverTime)||500}function u(t,n){const r=t.state.info,i=n.target||n.srcElement;if(!(i instanceof HTMLElement))return;if("SPAN"!==i.nodeName||void 0!==r.hoverTimeout)return;const o=i.getBoundingClientRect(),s=a((function(){clearTimeout(r.hoverTimeout),r.hoverTimeout=setTimeout(d,f)}),"onMouseMove"),u=a((function(){e.C.off(document,"mousemove",s),e.C.off(t.getWrapperElement(),"mouseout",u),clearTimeout(r.hoverTimeout),r.hoverTimeout=void 0}),"onMouseOut"),d=a((function(){e.C.off(document,"mousemove",s),e.C.off(t.getWrapperElement(),"mouseout",u),r.hoverTimeout=void 0,c(t,o)}),"onHover"),f=l(t);r.hoverTimeout=setTimeout(d,f),e.C.on(document,"mousemove",s),e.C.on(t.getWrapperElement(),"mouseout",u)}function c(e,t){const n=e.coordsChar({left:(t.left+t.right)/2,top:(t.top+t.bottom)/2}),r=e.state.info,{options:i}=r,o=i.render||e.getHelper(n,"info");if(o){const r=e.getTokenAt(n,!0);if(r){const a=o(r,i,e,n);a&&d(e,t,a)}}}function d(t,n,r){const i=document.createElement("div");i.className="CodeMirror-info",i.append(r),document.body.append(i);const o=i.getBoundingClientRect(),s=window.getComputedStyle(i),l=o.right-o.left+parseFloat(s.marginLeft)+parseFloat(s.marginRight),u=o.bottom-o.top+parseFloat(s.marginTop)+parseFloat(s.marginBottom);let c=n.bottom;u>window.innerHeight-n.bottom-15&&n.top>window.innerHeight-n.bottom&&(c=n.top-u),c<0&&(c=n.bottom);let d,f=Math.max(0,window.innerWidth-l-15);f>n.left&&(f=n.left),i.style.opacity="1",i.style.top=c+"px",i.style.left=f+"px";const p=a((function(){clearTimeout(d)}),"onMouseOverPopup"),h=a((function(){clearTimeout(d),d=setTimeout(m,200)}),"onMouseOut"),m=a((function(){e.C.off(i,"mouseover",p),e.C.off(i,"mouseout",h),e.C.off(t.getWrapperElement(),"mouseout",h),i.style.opacity?(i.style.opacity="0",setTimeout((()=>{i.parentNode&&i.remove()}),600)):i.parentNode&&i.remove()}),"hidePopup");e.C.on(i,"mouseover",p),e.C.on(i,"mouseout",h),e.C.on(t.getWrapperElement(),"mouseout",h)}e.C.defineOption("info",!1,((t,n,r)=>{if(r&&r!==e.C.Init){const n=t.state.info.onMouseOver;e.C.off(t.getWrapperElement(),"mouseover",n),clearTimeout(t.state.info.hoverTimeout),delete t.state.info}if(n){const r=t.state.info=s(n);r.onMouseOver=u.bind(null,t),e.C.on(t.getWrapperElement(),"mouseover",r.onMouseOver)}})),a(s,"createState"),a(l,"getHoverTime"),a(u,"onMouseOver"),a(c,"onMouseHover"),a(d,"showPopup")})?r.apply(t,i):r)||(e.exports=o)},9890:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[n(3573),n(535),n(2645),n(7421),n(6856),n(9196),n(1850),n(2635)],r=function(e,t,n,r,i,o,a,s){"use strict";var l=Object.defineProperty,u=(e,t)=>l(e,"name",{value:t,configurable:!0});function c(e,t,n){d(e,t,n),m(e,t,n,t.type)}function d(e,t,r){var i;b(e,(null===(i=t.fieldDef)||void 0===i?void 0:i.name)||"","field-name",r,(0,n.a)(t))}function f(e,t,r){var i;b(e,"@"+((null===(i=t.directiveDef)||void 0===i?void 0:i.name)||""),"directive-name",r,(0,n.b)(t))}function p(e,t,r){var i;b(e,(null===(i=t.argDef)||void 0===i?void 0:i.name)||"","arg-name",r,(0,n.c)(t)),m(e,t,r,t.inputType)}function h(e,t,r){var i;const o=(null===(i=t.enumValue)||void 0===i?void 0:i.name)||"";g(e,t,r,t.inputType),b(e,"."),b(e,o,"enum-value",r,(0,n.d)(t))}function m(t,r,i,o){const a=document.createElement("span");a.className="type-name-pill",o instanceof e.GraphQLNonNull?(g(a,r,i,o.ofType),b(a,"!")):o instanceof e.GraphQLList?(b(a,"["),g(a,r,i,o.ofType),b(a,"]")):b(a,(null==o?void 0:o.name)||"","type-name",i,(0,n.e)(r,o)),t.append(a)}function g(t,r,i,o){o instanceof e.GraphQLNonNull?(g(t,r,i,o.ofType),b(t,"!")):o instanceof e.GraphQLList?(b(t,"["),g(t,r,i,o.ofType),b(t,"]")):b(t,(null==o?void 0:o.name)||"","type-name",i,(0,n.e)(r,o))}function v(e,t,n){const{description:r}=n;if(r){const n=document.createElement("div");n.className="info-description",t.renderDescription?n.innerHTML=t.renderDescription(r):n.append(document.createTextNode(r)),e.append(n)}y(e,t,n)}function y(e,t,n){const r=n.deprecationReason;if(r){const n=document.createElement("div");n.className="info-deprecation",e.append(n);const i=document.createElement("span");i.className="info-deprecation-label",i.append(document.createTextNode("Deprecated")),n.append(i);const o=document.createElement("div");o.className="info-deprecation-reason",t.renderDescription?o.innerHTML=t.renderDescription(r):o.append(document.createTextNode(r)),n.append(o)}}function b(e,t){let n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"",r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{onClick:null},i=arguments.length>4&&void 0!==arguments[4]?arguments[4]:null;if(n){const{onClick:o}=r;let a;o?(a=document.createElement("a"),a.href="javascript:void 0",a.addEventListener("click",(e=>{o(i,e)}))):a=document.createElement("span"),a.className=n,a.append(document.createTextNode(t)),e.append(a)}else e.append(document.createTextNode(t))}t.C.registerHelper("info","graphql",((e,t)=>{if(!t.schema||!e.state)return;const{kind:r,step:i}=e.state,o=(0,n.g)(t.schema,e.state);if("Field"===r&&0===i&&o.fieldDef||"AliasedField"===r&&2===i&&o.fieldDef){const e=document.createElement("div");e.className="CodeMirror-info-header",c(e,o,t);const n=document.createElement("div");return n.append(e),v(n,t,o.fieldDef),n}if("Directive"===r&&1===i&&o.directiveDef){const e=document.createElement("div");e.className="CodeMirror-info-header",f(e,o,t);const n=document.createElement("div");return n.append(e),v(n,t,o.directiveDef),n}if("Argument"===r&&0===i&&o.argDef){const e=document.createElement("div");e.className="CodeMirror-info-header",p(e,o,t);const n=document.createElement("div");return n.append(e),v(n,t,o.argDef),n}if("EnumValue"===r&&o.enumValue&&o.enumValue.description){const e=document.createElement("div");e.className="CodeMirror-info-header",h(e,o,t);const n=document.createElement("div");return n.append(e),v(n,t,o.enumValue),n}if("NamedType"===r&&o.type&&o.type.description){const e=document.createElement("div");e.className="CodeMirror-info-header",g(e,o,t,o.type);const n=document.createElement("div");return n.append(e),v(n,t,o.type),n}})),u(c,"renderField"),u(d,"renderQualifiedField"),u(f,"renderDirective"),u(p,"renderArg"),u(h,"renderEnumValue"),u(m,"renderTypeAnnotation"),u(g,"renderType"),u(v,"renderDescription"),u(y,"renderDeprecation"),u(b,"text")},void 0===(o=r.apply(t,i))||(e.exports=o)},8888:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[t,n(535)],r=function(e,t){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.j=void 0;var n=Object.defineProperty,r=(e,t)=>n(e,"name",{value:t,configurable:!0});function i(e,t){return t.forEach((function(t){t&&"string"!=typeof t&&!Array.isArray(t)&&Object.keys(t).forEach((function(n){if("default"!==n&&!(n in e)){var r=Object.getOwnPropertyDescriptor(t,n);Object.defineProperty(e,n,r.get?r:{enumerable:!0,get:function(){return t[n]}})}}))})),Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}r(i,"_mergeNamespaces");var o,a={exports:{}};(o=t.a.exports).defineMode("javascript",(function(e,t){var n,i,a=e.indentUnit,s=t.statementIndent,l=t.jsonld,u=t.json||l,c=!1!==t.trackScope,d=t.typescript,f=t.wordCharacters||/[\w$\xa1-\uffff]/,p=function(){function e(e){return{type:e,style:"keyword"}}r(e,"kw");var t=e("keyword a"),n=e("keyword b"),i=e("keyword c"),o=e("keyword d"),a=e("operator"),s={type:"atom",style:"atom"};return{if:e("if"),while:t,with:t,else:n,do:n,try:n,finally:n,return:o,break:o,continue:o,new:e("new"),delete:i,void:i,throw:i,debugger:e("debugger"),var:e("var"),const:e("var"),let:e("var"),function:e("function"),catch:e("catch"),for:e("for"),switch:e("switch"),case:e("case"),default:e("default"),in:a,typeof:a,instanceof:a,true:s,false:s,null:s,undefined:s,NaN:s,Infinity:s,this:e("this"),class:e("class"),super:e("atom"),yield:i,export:e("export"),import:e("import"),extends:i,await:i}}(),h=/[+\-*&%=<>!?|~^@]/,m=/^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/;function g(e){for(var t,n=!1,r=!1;null!=(t=e.next());){if(!n){if("/"==t&&!r)return;"["==t?r=!0:r&&"]"==t&&(r=!1)}n=!n&&"\\"==t}}function v(e,t,r){return n=e,i=r,t}function y(e,t){var n=e.next();if('"'==n||"'"==n)return t.tokenize=b(n),t.tokenize(e,t);if("."==n&&e.match(/^\d[\d_]*(?:[eE][+\-]?[\d_]+)?/))return v("number","number");if("."==n&&e.match(".."))return v("spread","meta");if(/[\[\]{}\(\),;\:\.]/.test(n))return v(n);if("="==n&&e.eat(">"))return v("=>","operator");if("0"==n&&e.match(/^(?:x[\dA-Fa-f_]+|o[0-7_]+|b[01_]+)n?/))return v("number","number");if(/\d/.test(n))return e.match(/^[\d_]*(?:n|(?:\.[\d_]*)?(?:[eE][+\-]?[\d_]+)?)?/),v("number","number");if("/"==n)return e.eat("*")?(t.tokenize=E,E(e,t)):e.eat("/")?(e.skipToEnd(),v("comment","comment")):ot(e,t,1)?(g(e),e.match(/^\b(([gimyus])(?![gimyus]*\2))+\b/),v("regexp","string-2")):(e.eat("="),v("operator","operator",e.current()));if("`"==n)return t.tokenize=T,T(e,t);if("#"==n&&"!"==e.peek())return e.skipToEnd(),v("meta","meta");if("#"==n&&e.eatWhile(f))return v("variable","property");if("<"==n&&e.match("!--")||"-"==n&&e.match("->")&&!/\S/.test(e.string.slice(0,e.start)))return e.skipToEnd(),v("comment","comment");if(h.test(n))return">"==n&&t.lexical&&">"==t.lexical.type||(e.eat("=")?"!"!=n&&"="!=n||e.eat("="):/[<>*+\-|&?]/.test(n)&&(e.eat(n),">"==n&&e.eat(n))),"?"==n&&e.eat(".")?v("."):v("operator","operator",e.current());if(f.test(n)){e.eatWhile(f);var r=e.current();if("."!=t.lastType){if(p.propertyIsEnumerable(r)){var i=p[r];return v(i.type,i.style,r)}if("async"==r&&e.match(/^(\s|\/\*([^*]|\*(?!\/))*?\*\/)*[\[\(\w]/,!1))return v("async","keyword",r)}return v("variable","variable",r)}}function b(e){return function(t,n){var r,i=!1;if(l&&"@"==t.peek()&&t.match(m))return n.tokenize=y,v("jsonld-keyword","meta");for(;null!=(r=t.next())&&(r!=e||i);)i=!i&&"\\"==r;return i||(n.tokenize=y),v("string","string")}}function E(e,t){for(var n,r=!1;n=e.next();){if("/"==n&&r){t.tokenize=y;break}r="*"==n}return v("comment","comment")}function T(e,t){for(var n,r=!1;null!=(n=e.next());){if(!r&&("`"==n||"$"==n&&e.eat("{"))){t.tokenize=y;break}r=!r&&"\\"==n}return v("quasi","string-2",e.current())}r(g,"readRegexp"),r(v,"ret"),r(y,"tokenBase"),r(b,"tokenString"),r(E,"tokenComment"),r(T,"tokenQuasi");var w="([{}])";function C(e,t){t.fatArrowAt&&(t.fatArrowAt=null);var n=e.string.indexOf("=>",e.start);if(!(n<0)){if(d){var r=/:\s*(?:\w+(?:<[^>]*>|\[\])?|\{[^}]*\})\s*$/.exec(e.string.slice(e.start,n));r&&(n=r.index)}for(var i=0,o=!1,a=n-1;a>=0;--a){var s=e.string.charAt(a),l=w.indexOf(s);if(l>=0&&l<3){if(!i){++a;break}if(0==--i){"("==s&&(o=!0);break}}else if(l>=3&&l<6)++i;else if(f.test(s))o=!0;else if(/["'\/`]/.test(s))for(;;--a){if(0==a)return;if(e.string.charAt(a-1)==s&&"\\"!=e.string.charAt(a-2)){a--;break}}else if(o&&!i){++a;break}}o&&!i&&(t.fatArrowAt=a)}}r(C,"findFatArrow");var S={atom:!0,number:!0,variable:!0,string:!0,regexp:!0,this:!0,import:!0,"jsonld-keyword":!0};function x(e,t,n,r,i,o){this.indented=e,this.column=t,this.type=n,this.prev=i,this.info=o,null!=r&&(this.align=r)}function k(e,t){if(!c)return!1;for(var n=e.localVars;n;n=n.next)if(n.name==t)return!0;for(var r=e.context;r;r=r.prev)for(n=r.vars;n;n=n.next)if(n.name==t)return!0}function N(e,t,n,r,i){var o=e.cc;for(_.state=e,_.stream=i,_.marked=null,_.cc=o,_.style=t,e.lexical.hasOwnProperty("align")||(e.lexical.align=!0);;)if((o.length?o.pop():u?z:H)(n,r)){for(;o.length&&o[o.length-1].lex;)o.pop()();return _.marked?_.marked:"variable"==n&&k(e,r)?"variable-2":t}}r(x,"JSLexical"),r(k,"inScope"),r(N,"parseJS");var _={state:null,column:null,marked:null,cc:null};function O(){for(var e=arguments.length-1;e>=0;e--)_.cc.push(arguments[e])}function I(){return O.apply(null,arguments),!0}function D(e,t){for(var n=t;n;n=n.next)if(n.name==e)return!0;return!1}function L(e){var n=_.state;if(_.marked="def",c){if(n.context)if("var"==n.lexical.info&&n.context&&n.context.block){var r=A(e,n.context);if(null!=r)return void(n.context=r)}else if(!D(e,n.localVars))return void(n.localVars=new F(e,n.localVars));t.globalVars&&!D(e,n.globalVars)&&(n.globalVars=new F(e,n.globalVars))}}function A(e,t){if(t){if(t.block){var n=A(e,t.prev);return n?n==t.prev?t:new R(n,t.vars,!0):null}return D(e,t.vars)?t:new R(t.prev,new F(e,t.vars),!1)}return null}function M(e){return"public"==e||"private"==e||"protected"==e||"abstract"==e||"readonly"==e}function R(e,t,n){this.prev=e,this.vars=t,this.block=n}function F(e,t){this.name=e,this.next=t}r(O,"pass"),r(I,"cont"),r(D,"inList"),r(L,"register"),r(A,"registerVarScoped"),r(M,"isModifier"),r(R,"Context"),r(F,"Var");var P=new F("this",new F("arguments",null));function j(){_.state.context=new R(_.state.context,_.state.localVars,!1),_.state.localVars=P}function V(){_.state.context=new R(_.state.context,_.state.localVars,!0),_.state.localVars=null}function U(){_.state.localVars=_.state.context.vars,_.state.context=_.state.context.prev}function B(e,t){var n=r((function(){var n=_.state,r=n.indented;if("stat"==n.lexical.type)r=n.lexical.indented;else for(var i=n.lexical;i&&")"==i.type&&i.align;i=i.prev)r=i.indented;n.lexical=new x(r,_.stream.column(),e,null,n.lexical,t)}),"result");return n.lex=!0,n}function $(){var e=_.state;e.lexical.prev&&(")"==e.lexical.type&&(e.indented=e.lexical.indented),e.lexical=e.lexical.prev)}function q(e){function t(n){return n==e?I():";"==e||"}"==n||")"==n||"]"==n?O():I(t)}return r(t,"exp"),t}function H(e,t){return"var"==e?I(B("vardef",t),Oe,q(";"),$):"keyword a"==e?I(B("form"),K,H,$):"keyword b"==e?I(B("form"),H,$):"keyword d"==e?_.stream.match(/^\s*$/,!1)?I():I(B("stat"),X,q(";"),$):"debugger"==e?I(q(";")):"{"==e?I(B("}"),V,pe,$,U):";"==e?I():"if"==e?("else"==_.state.lexical.info&&_.state.cc[_.state.cc.length-1]==$&&_.state.cc.pop()(),I(B("form"),K,H,$,Re)):"function"==e?I(Ve):"for"==e?I(B("form"),V,Fe,H,U,$):"class"==e||d&&"interface"==t?(_.marked="keyword",I(B("form","class"==e?e:t),He,$)):"variable"==e?d&&"declare"==t?(_.marked="keyword",I(H)):d&&("module"==t||"enum"==t||"type"==t)&&_.stream.match(/^\s*\w/,!1)?(_.marked="keyword","enum"==t?I(nt):"type"==t?I(Be,q("operator"),ye,q(";")):I(B("form"),Ie,q("{"),B("}"),pe,$,$)):d&&"namespace"==t?(_.marked="keyword",I(B("form"),z,H,$)):d&&"abstract"==t?(_.marked="keyword",I(H)):I(B("stat"),ae):"switch"==e?I(B("form"),K,q("{"),B("}","switch"),V,pe,$,$,U):"case"==e?I(z,q(":")):"default"==e?I(q(":")):"catch"==e?I(B("form"),j,G,H,$,U):"export"==e?I(B("stat"),Ke,$):"import"==e?I(B("stat"),Xe,$):"async"==e?I(H):"@"==t?I(z,H):O(B("stat"),z,q(";"),$)}function G(e){if("("==e)return I($e,q(")"))}function z(e,t){return Q(e,t,!1)}function W(e,t){return Q(e,t,!0)}function K(e){return"("!=e?O():I(B(")"),X,q(")"),$)}function Q(e,t,n){if(_.state.fatArrowAt==_.stream.start){var r=n?ne:te;if("("==e)return I(j,B(")"),de($e,")"),$,q("=>"),r,U);if("variable"==e)return O(j,Ie,q("=>"),r,U)}var i=n?J:Y;return S.hasOwnProperty(e)?I(i):"function"==e?I(Ve,i):"class"==e||d&&"interface"==t?(_.marked="keyword",I(B("form"),qe,$)):"keyword c"==e||"async"==e?I(n?W:z):"("==e?I(B(")"),X,q(")"),$,i):"operator"==e||"spread"==e?I(n?W:z):"["==e?I(B("]"),tt,$,i):"{"==e?fe(le,"}",null,i):"quasi"==e?O(Z,i):"new"==e?I(re(n)):I()}function X(e){return e.match(/[;\}\)\],]/)?O():O(z)}function Y(e,t){return","==e?I(X):J(e,t,!1)}function J(e,t,n){var r=0==n?Y:J,i=0==n?z:W;return"=>"==e?I(j,n?ne:te,U):"operator"==e?/\+\+|--/.test(t)||d&&"!"==t?I(r):d&&"<"==t&&_.stream.match(/^([^<>]|<[^<>]*>)*>\s*\(/,!1)?I(B(">"),de(ye,">"),$,r):"?"==t?I(z,q(":"),i):I(i):"quasi"==e?O(Z,r):";"!=e?"("==e?fe(W,")","call",r):"."==e?I(se,r):"["==e?I(B("]"),X,q("]"),$,r):d&&"as"==t?(_.marked="keyword",I(ye,r)):"regexp"==e?(_.state.lastType=_.marked="operator",_.stream.backUp(_.stream.pos-_.stream.start-1),I(i)):void 0:void 0}function Z(e,t){return"quasi"!=e?O():"${"!=t.slice(t.length-2)?I(Z):I(X,ee)}function ee(e){if("}"==e)return _.marked="string-2",_.state.tokenize=T,I(Z)}function te(e){return C(_.stream,_.state),O("{"==e?H:z)}function ne(e){return C(_.stream,_.state),O("{"==e?H:W)}function re(e){return function(t){return"."==t?I(e?oe:ie):"variable"==t&&d?I(ke,e?J:Y):O(e?W:z)}}function ie(e,t){if("target"==t)return _.marked="keyword",I(Y)}function oe(e,t){if("target"==t)return _.marked="keyword",I(J)}function ae(e){return":"==e?I($,H):O(Y,q(";"),$)}function se(e){if("variable"==e)return _.marked="property",I()}function le(e,t){return"async"==e?(_.marked="property",I(le)):"variable"==e||"keyword"==_.style?(_.marked="property","get"==t||"set"==t?I(ue):(d&&_.state.fatArrowAt==_.stream.start&&(n=_.stream.match(/^\s*:\s*/,!1))&&(_.state.fatArrowAt=_.stream.pos+n[0].length),I(ce))):"number"==e||"string"==e?(_.marked=l?"property":_.style+" property",I(ce)):"jsonld-keyword"==e?I(ce):d&&M(t)?(_.marked="keyword",I(le)):"["==e?I(z,he,q("]"),ce):"spread"==e?I(W,ce):"*"==t?(_.marked="keyword",I(le)):":"==e?O(ce):void 0;var n}function ue(e){return"variable"!=e?O(ce):(_.marked="property",I(Ve))}function ce(e){return":"==e?I(W):"("==e?O(Ve):void 0}function de(e,t,n){function i(r,o){if(n?n.indexOf(r)>-1:","==r){var a=_.state.lexical;return"call"==a.info&&(a.pos=(a.pos||0)+1),I((function(n,r){return n==t||r==t?O():O(e)}),i)}return r==t||o==t?I():n&&n.indexOf(";")>-1?O(e):I(q(t))}return r(i,"proceed"),function(n,r){return n==t||r==t?I():O(e,i)}}function fe(e,t,n){for(var r=3;r"),ye):"quasi"==e?O(we,xe):void 0}function be(e){if("=>"==e)return I(ye)}function Ee(e){return e.match(/[\}\)\]]/)?I():","==e||";"==e?I(Ee):O(Te,Ee)}function Te(e,t){return"variable"==e||"keyword"==_.style?(_.marked="property",I(Te)):"?"==t||"number"==e||"string"==e?I(Te):":"==e?I(ye):"["==e?I(q("variable"),me,q("]"),Te):"("==e?O(Ue,Te):e.match(/[;\}\)\],]/)?void 0:I()}function we(e,t){return"quasi"!=e?O():"${"!=t.slice(t.length-2)?I(we):I(ye,Ce)}function Ce(e){if("}"==e)return _.marked="string-2",_.state.tokenize=T,I(we)}function Se(e,t){return"variable"==e&&_.stream.match(/^\s*[?:]/,!1)||"?"==t?I(Se):":"==e?I(ye):"spread"==e?I(Se):O(ye)}function xe(e,t){return"<"==t?I(B(">"),de(ye,">"),$,xe):"|"==t||"."==e||"&"==t?I(ye):"["==e?I(ye,q("]"),xe):"extends"==t||"implements"==t?(_.marked="keyword",I(ye)):"?"==t?I(ye,q(":"),ye):void 0}function ke(e,t){if("<"==t)return I(B(">"),de(ye,">"),$,xe)}function Ne(){return O(ye,_e)}function _e(e,t){if("="==t)return I(ye)}function Oe(e,t){return"enum"==t?(_.marked="keyword",I(nt)):O(Ie,he,Ae,Me)}function Ie(e,t){return d&&M(t)?(_.marked="keyword",I(Ie)):"variable"==e?(L(t),I()):"spread"==e?I(Ie):"["==e?fe(Le,"]"):"{"==e?fe(De,"}"):void 0}function De(e,t){return"variable"!=e||_.stream.match(/^\s*:/,!1)?("variable"==e&&(_.marked="property"),"spread"==e?I(Ie):"}"==e?O():"["==e?I(z,q("]"),q(":"),De):I(q(":"),Ie,Ae)):(L(t),I(Ae))}function Le(){return O(Ie,Ae)}function Ae(e,t){if("="==t)return I(W)}function Me(e){if(","==e)return I(Oe)}function Re(e,t){if("keyword b"==e&&"else"==t)return I(B("form","else"),H,$)}function Fe(e,t){return"await"==t?I(Fe):"("==e?I(B(")"),Pe,$):void 0}function Pe(e){return"var"==e?I(Oe,je):"variable"==e?I(je):O(je)}function je(e,t){return")"==e?I():";"==e?I(je):"in"==t||"of"==t?(_.marked="keyword",I(z,je)):O(z,je)}function Ve(e,t){return"*"==t?(_.marked="keyword",I(Ve)):"variable"==e?(L(t),I(Ve)):"("==e?I(j,B(")"),de($e,")"),$,ge,H,U):d&&"<"==t?I(B(">"),de(Ne,">"),$,Ve):void 0}function Ue(e,t){return"*"==t?(_.marked="keyword",I(Ue)):"variable"==e?(L(t),I(Ue)):"("==e?I(j,B(")"),de($e,")"),$,ge,U):d&&"<"==t?I(B(">"),de(Ne,">"),$,Ue):void 0}function Be(e,t){return"keyword"==e||"variable"==e?(_.marked="type",I(Be)):"<"==t?I(B(">"),de(Ne,">"),$):void 0}function $e(e,t){return"@"==t&&I(z,$e),"spread"==e?I($e):d&&M(t)?(_.marked="keyword",I($e)):d&&"this"==e?I(he,Ae):O(Ie,he,Ae)}function qe(e,t){return"variable"==e?He(e,t):Ge(e,t)}function He(e,t){if("variable"==e)return L(t),I(Ge)}function Ge(e,t){return"<"==t?I(B(">"),de(Ne,">"),$,Ge):"extends"==t||"implements"==t||d&&","==e?("implements"==t&&(_.marked="keyword"),I(d?ye:z,Ge)):"{"==e?I(B("}"),ze,$):void 0}function ze(e,t){return"async"==e||"variable"==e&&("static"==t||"get"==t||"set"==t||d&&M(t))&&_.stream.match(/^\s+[\w$\xa1-\uffff]/,!1)?(_.marked="keyword",I(ze)):"variable"==e||"keyword"==_.style?(_.marked="property",I(We,ze)):"number"==e||"string"==e?I(We,ze):"["==e?I(z,he,q("]"),We,ze):"*"==t?(_.marked="keyword",I(ze)):d&&"("==e?O(Ue,ze):";"==e||","==e?I(ze):"}"==e?I():"@"==t?I(z,ze):void 0}function We(e,t){if("!"==t)return I(We);if("?"==t)return I(We);if(":"==e)return I(ye,Ae);if("="==t)return I(W);var n=_.state.lexical.prev;return O(n&&"interface"==n.info?Ue:Ve)}function Ke(e,t){return"*"==t?(_.marked="keyword",I(et,q(";"))):"default"==t?(_.marked="keyword",I(z,q(";"))):"{"==e?I(de(Qe,"}"),et,q(";")):O(H)}function Qe(e,t){return"as"==t?(_.marked="keyword",I(q("variable"))):"variable"==e?O(W,Qe):void 0}function Xe(e){return"string"==e?I():"("==e?O(z):"."==e?O(Y):O(Ye,Je,et)}function Ye(e,t){return"{"==e?fe(Ye,"}"):("variable"==e&&L(t),"*"==t&&(_.marked="keyword"),I(Ze))}function Je(e){if(","==e)return I(Ye,Je)}function Ze(e,t){if("as"==t)return _.marked="keyword",I(Ye)}function et(e,t){if("from"==t)return _.marked="keyword",I(z)}function tt(e){return"]"==e?I():O(de(W,"]"))}function nt(){return O(B("form"),Ie,q("{"),B("}"),de(rt,"}"),$,$)}function rt(){return O(Ie,Ae)}function it(e,t){return"operator"==e.lastType||","==e.lastType||h.test(t.charAt(0))||/[,.]/.test(t.charAt(0))}function ot(e,t,n){return t.tokenize==y&&/^(?:operator|sof|keyword [bcd]|case|new|export|default|spread|[\[{}\(,;:]|=>)$/.test(t.lastType)||"quasi"==t.lastType&&/\{\s*$/.test(e.string.slice(0,e.pos-(n||0)))}return r(j,"pushcontext"),r(V,"pushblockcontext"),j.lex=V.lex=!0,r(U,"popcontext"),U.lex=!0,r(B,"pushlex"),r($,"poplex"),$.lex=!0,r(q,"expect"),r(H,"statement"),r(G,"maybeCatchBinding"),r(z,"expression"),r(W,"expressionNoComma"),r(K,"parenExpr"),r(Q,"expressionInner"),r(X,"maybeexpression"),r(Y,"maybeoperatorComma"),r(J,"maybeoperatorNoComma"),r(Z,"quasi"),r(ee,"continueQuasi"),r(te,"arrowBody"),r(ne,"arrowBodyNoComma"),r(re,"maybeTarget"),r(ie,"target"),r(oe,"targetNoComma"),r(ae,"maybelabel"),r(se,"property"),r(le,"objprop"),r(ue,"getterSetter"),r(ce,"afterprop"),r(de,"commasep"),r(fe,"contCommasep"),r(pe,"block"),r(he,"maybetype"),r(me,"maybetypeOrIn"),r(ge,"mayberettype"),r(ve,"isKW"),r(ye,"typeexpr"),r(be,"maybeReturnType"),r(Ee,"typeprops"),r(Te,"typeprop"),r(we,"quasiType"),r(Ce,"continueQuasiType"),r(Se,"typearg"),r(xe,"afterType"),r(ke,"maybeTypeArgs"),r(Ne,"typeparam"),r(_e,"maybeTypeDefault"),r(Oe,"vardef"),r(Ie,"pattern"),r(De,"proppattern"),r(Le,"eltpattern"),r(Ae,"maybeAssign"),r(Me,"vardefCont"),r(Re,"maybeelse"),r(Fe,"forspec"),r(Pe,"forspec1"),r(je,"forspec2"),r(Ve,"functiondef"),r(Ue,"functiondecl"),r(Be,"typename"),r($e,"funarg"),r(qe,"classExpression"),r(He,"className"),r(Ge,"classNameAfter"),r(ze,"classBody"),r(We,"classfield"),r(Ke,"afterExport"),r(Qe,"exportField"),r(Xe,"afterImport"),r(Ye,"importSpec"),r(Je,"maybeMoreImports"),r(Ze,"maybeAs"),r(et,"maybeFrom"),r(tt,"arrayLiteral"),r(nt,"enumdef"),r(rt,"enummember"),r(it,"isContinuedStatement"),r(ot,"expressionAllowed"),{startState:function(e){var n={tokenize:y,lastType:"sof",cc:[],lexical:new x((e||0)-a,0,"block",!1),localVars:t.localVars,context:t.localVars&&new R(null,null,!1),indented:e||0};return t.globalVars&&"object"==typeof t.globalVars&&(n.globalVars=t.globalVars),n},token:function(e,t){if(e.sol()&&(t.lexical.hasOwnProperty("align")||(t.lexical.align=!1),t.indented=e.indentation(),C(e,t)),t.tokenize!=E&&e.eatSpace())return null;var r=t.tokenize(e,t);return"comment"==n?r:(t.lastType="operator"!=n||"++"!=i&&"--"!=i?n:"incdec",N(t,r,n,i,e))},indent:function(e,n){if(e.tokenize==E||e.tokenize==T)return o.Pass;if(e.tokenize!=y)return 0;var r,i=n&&n.charAt(0),l=e.lexical;if(!/^\s*else\b/.test(n))for(var u=e.cc.length-1;u>=0;--u){var c=e.cc[u];if(c==$)l=l.prev;else if(c!=Re&&c!=U)break}for(;("stat"==l.type||"form"==l.type)&&("}"==i||(r=e.cc[e.cc.length-1])&&(r==Y||r==J)&&!/^[,\.=+\-*:?[\(]/.test(n));)l=l.prev;s&&")"==l.type&&"stat"==l.prev.type&&(l=l.prev);var d=l.type,f=i==d;return"vardef"==d?l.indented+("operator"==e.lastType||","==e.lastType?l.info.length+1:0):"form"==d&&"{"==i?l.indented:"form"==d?l.indented+a:"stat"==d?l.indented+(it(e,n)?s||a:0):"switch"!=l.info||f||0==t.doubleIndentSwitch?l.align?l.column+(f?0:1):l.indented+(f?0:a):l.indented+(/^(?:case|default)\b/.test(n)?a:2*a)},electricInput:/^\s*(?:case .*?:|default:|\{|\})$/,blockCommentStart:u?null:"/*",blockCommentEnd:u?null:"*/",blockCommentContinue:u?null:" * ",lineComment:u?null:"//",fold:"brace",closeBrackets:"()[]{}''\"\"``",helperType:u?"json":"javascript",jsonldMode:l,jsonMode:u,expressionAllowed:ot,skipExpression:function(e){N(e,"atom","atom","true",new o.StringStream("",2,null))}}})),o.registerHelper("wordChars","javascript",/[\w$]/),o.defineMIME("text/javascript","javascript"),o.defineMIME("text/ecmascript","javascript"),o.defineMIME("application/javascript","javascript"),o.defineMIME("application/x-javascript","javascript"),o.defineMIME("application/ecmascript","javascript"),o.defineMIME("application/json",{name:"javascript",json:!0}),o.defineMIME("application/x-json",{name:"javascript",json:!0}),o.defineMIME("application/manifest+json",{name:"javascript",json:!0}),o.defineMIME("application/ld+json",{name:"javascript",jsonld:!0}),o.defineMIME("text/typescript",{name:"javascript",typescript:!0}),o.defineMIME("application/typescript",{name:"javascript",typescript:!0});var s=i({__proto__:null,default:a.exports},[a.exports]);e.j=s},void 0===(o=r.apply(t,i))||(e.exports=o)},4471:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[t,n(535),n(8058)],void 0===(o="function"==typeof(r=function(e,t,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.j=void 0;var r=Object.defineProperty,i=(e,t)=>r(e,"name",{value:t,configurable:!0});function o(e,t){return t.forEach((function(t){t&&"string"!=typeof t&&!Array.isArray(t)&&Object.keys(t).forEach((function(n){if("default"!==n&&!(n in e)){var r=Object.getOwnPropertyDescriptor(t,n);Object.defineProperty(e,n,r.get?r:{enumerable:!0,get:function(){return t[n]}})}}))})),Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}i(o,"_mergeNamespaces");var a={exports:{}};!function(e){function t(e,t,n,r,i){e.openDialog?e.openDialog(t,i,{value:r,selectValueOnOpen:!0,bottom:e.options.search.bottom}):i(prompt(n,r))}function n(e){return e.phrase("Jump to line:")+' '+e.phrase("(Use line:column or scroll% syntax)")+""}function r(e,t){var n=Number(t);return/^[-+]/.test(t)?e.getCursor().line+n:n-1}e.defineOption("search",{bottom:!1}),i(t,"dialog"),i(n,"getJumpDialog"),i(r,"interpretLine"),e.commands.jumpToLine=function(e){var i=e.getCursor();t(e,n(e),e.phrase("Jump to line:"),i.line+1+":"+i.ch,(function(t){var n;if(t)if(n=/^\s*([\+\-]?\d+)\s*\:\s*(\d+)\s*$/.exec(t))e.setCursor(r(e,n[1]),Number(n[2]));else if(n=/^\s*([\+\-]?\d+(\.\d+)?)\%\s*/.exec(t)){var o=Math.round(e.lineCount()*Number(n[1])/100);/^[-+]/.test(n[1])&&(o=i.line+o+1),e.setCursor(o-1,i.ch)}else(n=/^\s*\:?\s*([\+\-]?\d+)\s*/.exec(t))&&e.setCursor(r(e,n[1]),i.ch)}))},e.keyMap.default["Alt-G"]="jumpToLine"}(t.a.exports,n.a.exports);var s=o({__proto__:null,default:a.exports},[a.exports]);e.j=s})?r.apply(t,i):r)||(e.exports=o)},5980:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[n(535),n(2645),n(6856),n(9196),n(3573),n(1850),n(2635)],void 0===(o="function"==typeof(r=function(e,t,n,r,i,o,a){"use strict";var s=Object.defineProperty,l=(e,t)=>s(e,"name",{value:t,configurable:!0});function u(e,t){const n=t.target||t.srcElement;if(!(n instanceof HTMLElement))return;if("SPAN"!==(null==n?void 0:n.nodeName))return;const r=n.getBoundingClientRect(),i={left:(r.left+r.right)/2,top:(r.top+r.bottom)/2};e.state.jump.cursor=i,e.state.jump.isHoldingModifier&&h(e)}function c(e){e.state.jump.isHoldingModifier||!e.state.jump.cursor?e.state.jump.isHoldingModifier&&e.state.jump.marker&&m(e):e.state.jump.cursor=null}function d(t,n){if(t.state.jump.isHoldingModifier||!p(n.key))return;t.state.jump.isHoldingModifier=!0,t.state.jump.cursor&&h(t);const r=l((a=>{a.code===n.code&&(t.state.jump.isHoldingModifier=!1,t.state.jump.marker&&m(t),e.C.off(document,"keyup",r),e.C.off(document,"click",i),t.off("mousedown",o))}),"onKeyUp"),i=l((e=>{const{destination:n,options:r}=t.state.jump;n&&r.onClick(n,e)}),"onClick"),o=l(((e,n)=>{t.state.jump.destination&&(n.codemirrorIgnore=!0)}),"onMouseDown");e.C.on(document,"keyup",r),e.C.on(document,"click",i),t.on("mousedown",o)}e.C.defineOption("jump",!1,((t,n,r)=>{if(r&&r!==e.C.Init){const n=t.state.jump.onMouseOver;e.C.off(t.getWrapperElement(),"mouseover",n);const r=t.state.jump.onMouseOut;e.C.off(t.getWrapperElement(),"mouseout",r),e.C.off(document,"keydown",t.state.jump.onKeyDown),delete t.state.jump}if(n){const r=t.state.jump={options:n,onMouseOver:u.bind(null,t),onMouseOut:c.bind(null,t),onKeyDown:d.bind(null,t)};e.C.on(t.getWrapperElement(),"mouseover",r.onMouseOver),e.C.on(t.getWrapperElement(),"mouseout",r.onMouseOut),e.C.on(document,"keydown",r.onKeyDown)}})),l(u,"onMouseOver"),l(c,"onMouseOut"),l(d,"onKeyDown");const f="undefined"!=typeof navigator&&navigator&&navigator.appVersion.includes("Mac");function p(e){return e===(f?"Meta":"Control")}function h(e){if(e.state.jump.marker)return;const{cursor:t,options:n}=e.state.jump,r=e.coordsChar(t),i=e.getTokenAt(r,!0),o=n.getDestination||e.getHelper(r,"jump");if(o){const t=o(i,n,e);if(t){const n=e.markText({line:r.line,ch:i.start},{line:r.line,ch:i.end},{className:"CodeMirror-jump-token"});e.state.jump.marker=n,e.state.jump.destination=t}}}function m(e){const{marker:t}=e.state.jump;e.state.jump.marker=null,e.state.jump.destination=null,t.clear()}l(p,"isJumpModifier"),l(h,"enableJumpMode"),l(m,"disableJumpMode"),e.C.registerHelper("jump","graphql",((e,n)=>{if(!n.schema||!n.onClick||!e.state)return;const{state:r}=e,{kind:i,step:o}=r,a=(0,t.g)(n.schema,r);return"Field"===i&&0===o&&a.fieldDef||"AliasedField"===i&&2===o&&a.fieldDef?(0,t.a)(a):"Directive"===i&&1===o&&a.directiveDef?(0,t.b)(a):"Argument"===i&&0===o&&a.argDef?(0,t.c)(a):"EnumValue"===i&&a.enumValue?(0,t.d)(a):"NamedType"===i&&a.type?(0,t.e)(a):void 0}))})?r.apply(t,i):r)||(e.exports=o)},9444:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[n(535),n(3573),n(6856),n(5609),n(9196),n(1850)],r=function(e,t,n,r,i,o){"use strict";var a=Object.defineProperty,s=(e,t)=>a(e,"name",{value:t,configurable:!0});const l=[t.LoneSchemaDefinitionRule,t.UniqueOperationTypesRule,t.UniqueTypeNamesRule,t.UniqueEnumValueNamesRule,t.UniqueFieldDefinitionNamesRule,t.UniqueDirectiveNamesRule,t.KnownTypeNamesRule,t.KnownDirectivesRule,t.UniqueDirectivesPerLocationRule,t.PossibleTypeExtensionsRule,t.UniqueArgumentNamesRule,t.UniqueInputFieldNamesRule];function u(e,n,r,i,o){const a=t.specifiedRules.filter((e=>e!==t.NoUnusedFragmentsRule&&e!==t.ExecutableDefinitionsRule&&(!i||e!==t.KnownFragmentNamesRule)));return r&&Array.prototype.push.apply(a,r),o&&Array.prototype.push.apply(a,l),(0,t.validate)(e,n,a).filter((e=>{if(e.message.includes("Unknown directive")&&e.nodes){const n=e.nodes[0];if(n&&n.kind===t.Kind.DIRECTIVE){const e=n.name.value;if("arguments"===e||"argumentDefinitions"===e)return!1}}return!0}))}s(u,"validateWithCustomRules");const c={["Error"]:1,["Warning"]:2,["Information"]:3,["Hint"]:4},d=s(((e,t)=>{if(!e)throw new Error(t)}),"invariant");function f(e){let n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,r=arguments.length>2?arguments[2]:void 0,i=arguments.length>3?arguments[3]:void 0,o=arguments.length>4?arguments[4]:void 0;var a,s;let l=null,u="";o&&(u="string"==typeof o?o:o.reduce(((e,n)=>e+(0,t.print)(n)+"\n\n"),""));const d=u?`${e}\n\n${u}`:e;try{l=(0,t.parse)(d)}catch(e){if(e instanceof t.GraphQLError){const t=m(null!==(s=null===(a=e.locations)||void 0===a?void 0:a[0])&&void 0!==s?s:{line:0,column:0},d);return[{severity:c.Error,message:e.message,source:"GraphQL: Syntax",range:t}]}throw e}return p(l,n,r,i)}function p(e){let n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;if(!n)return[];const r=u(n,e,arguments.length>2?arguments[2]:void 0,arguments.length>3?arguments[3]:void 0).flatMap((e=>h(e,c.Error,"Validation"))),i=(0,t.validate)(n,e,[t.NoDeprecatedCustomRule]).flatMap((e=>h(e,c.Warning,"Deprecation")));return r.concat(i)}function h(e,t,n){if(!e.nodes)return[];const i=[];for(const[o,a]of e.nodes.entries()){const s="Variable"!==a.kind&&"name"in a&&void 0!==a.name?a.name:"variable"in a&&void 0!==a.variable?a.variable:a;if(s){d(e.locations,"GraphQL validation error requires locations.");const a=e.locations[o],l=g(s),u=a.column+(l.end-l.start);i.push({source:`GraphQL: ${n}`,message:e.message,severity:t,range:new r.R(new r.P(a.line-1,a.column-1),new r.P(a.line-1,u))})}}return i}function m(e,t){const i=(0,n.o)(),o=i.startState(),a=t.split("\n");d(a.length>=e.line,"Query text must have more lines than where the error happened");let s=null;for(let t=0;t{const{schema:r,validationRules:i,externalFragments:o}=n;return f(t,r,i,void 0,o).map((t=>({message:t.message,severity:t.severity?v[t.severity-1]:v[0],type:t.source?y[t.source]:void 0,from:e.C.Pos(t.range.start.line,t.range.start.character),to:e.C.Pos(t.range.end.line,t.range.end.character)})))}))},void 0===(o=r.apply(t,i))||(e.exports=o)},8535:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[n(535),n(3573),n(6856),n(9196),n(1850)],void 0===(o="function"==typeof(r=function(e,t,n,r,i){"use strict";var o=Object.defineProperty,a=(e,t)=>o(e,"name",{value:t,configurable:!0});function s(e){l=e,u=e.length,c=d=f=-1,S(),x();const t=m();return E("EOF"),t}let l,u,c,d,f,p,h;function m(){const e=c,t=[];if(E("{"),!C("}")){do{t.push(g())}while(C(","));E("}")}return{kind:"Object",start:e,end:f,members:t}}function g(){const e=c,t="String"===h?b():null;E("String"),E(":");const n=y();return{kind:"Member",start:e,end:f,key:t,value:n}}function v(){const e=c,t=[];if(E("["),!C("]")){do{t.push(y())}while(C(","));E("]")}return{kind:"Array",start:e,end:f,values:t}}function y(){switch(h){case"[":return v();case"{":return m();case"String":case"Number":case"Boolean":case"Null":const e=b();return x(),e}E("Value")}function b(){return{kind:h,start:c,end:d,value:JSON.parse(l.slice(c,d))}}function E(e){if(h===e)return void x();let t;if("EOF"===h)t="[end of file]";else if(d-c>1)t="`"+l.slice(c,d)+"`";else{const e=l.slice(c).match(/^.+?\b/);t="`"+(e?e[0]:l[c])+"`"}throw w(`Expected ${e} but found ${t}.`)}a(s,"jsonParse"),a(m,"parseObj"),a(g,"parseMember"),a(v,"parseArr"),a(y,"parseVal"),a(b,"curToken"),a(E,"expect");class T extends Error{constructor(e,t){super(e),this.position=t}}function w(e){return new T(e,{start:c,end:d})}function C(e){if(h===e)return x(),!0}function S(){return d31;)if(92===p)switch(p=S(),p){case 34:case 47:case 92:case 98:case 102:case 110:case 114:case 116:S();break;case 117:S(),N(),N(),N(),N();break;default:throw w("Bad character escape sequence.")}else{if(d===u)throw w("Unterminated string.");S()}if(34!==p)throw w("Unterminated string.");S()}function N(){if(p>=48&&p<=57||p>=65&&p<=70||p>=97&&p<=102)return S();throw w("Expected hexadecimal digit.")}function _(){45===p&&S(),48===p?S():O(),46===p&&(S(),O()),69!==p&&101!==p||(p=S(),43!==p&&45!==p||S(),O())}function O(){if(p<48||p>57)throw w("Expected decimal digit.");do{S()}while(p>=48&&p<=57)}function I(e,t,n){var r;const i=[];for(const o of n.members)if(o){const n=null===(r=o.key)||void 0===r?void 0:r.value,a=t[n];if(a)for(const[t,n]of D(a,o.value))i.push(L(e,t,n));else i.push(L(e,o.key,`Variable "$${n}" does not appear in any GraphQL query.`))}return i}function D(e,n){if(!e||!n)return[];if(e instanceof t.GraphQLNonNull)return"Null"===n.kind?[[n,`Type "${e}" is non-nullable and cannot be null.`]]:D(e.ofType,n);if("Null"===n.kind)return[];if(e instanceof t.GraphQLList){const t=e.ofType;return"Array"===n.kind?M(n.values||[],(e=>D(t,e))):D(t,n)}if(e instanceof t.GraphQLInputObjectType){if("Object"!==n.kind)return[[n,`Type "${e}" must be an Object.`]];const r=Object.create(null),i=M(n.members,(t=>{var n;const i=null===(n=null==t?void 0:t.key)||void 0===n?void 0:n.value;r[i]=!0;const o=e.getFields()[i];return o?D(o?o.type:void 0,t.value):[[t.key,`Type "${e}" does not have a field "${i}".`]]}));for(const o of Object.keys(e.getFields())){const a=e.getFields()[o];!r[o]&&a.type instanceof t.GraphQLNonNull&&!a.defaultValue&&i.push([n,`Object of type "${e}" is missing required field "${o}".`])}return i}return"Boolean"===e.name&&"Boolean"!==n.kind||"String"===e.name&&"String"!==n.kind||"ID"===e.name&&"Number"!==n.kind&&"String"!==n.kind||"Float"===e.name&&"Number"!==n.kind||"Int"===e.name&&("Number"!==n.kind||(0|n.value)!==n.value)||(e instanceof t.GraphQLEnumType||e instanceof t.GraphQLScalarType)&&("String"!==n.kind&&"Number"!==n.kind&&"Boolean"!==n.kind&&"Null"!==n.kind||A(e.parseValue(n.value)))?[[n,`Expected value of type "${e}".`]]:[]}function L(e,t,n){return{message:n,severity:"error",type:"validation",from:e.posFromIndex(t.start),to:e.posFromIndex(t.end)}}function A(e){return null==e||e!=e}function M(e,t){return Array.prototype.concat.apply([],e.map(t))}a(T,"JSONSyntaxError"),a(w,"syntaxError"),a(C,"skip"),a(S,"ch"),a(x,"lex"),a(k,"readString"),a(N,"readHex"),a(_,"readNumber"),a(O,"readDigits"),e.C.registerHelper("lint","graphql-variables",((e,t,n)=>{if(!e)return[];let r;try{r=s(e)}catch(e){if(e instanceof T)return[L(n,e.position,e.message)];throw e}const{variableToType:i}=t;return i?I(n,i,r):[]})),a(I,"validateVariables"),a(D,"validateValue"),a(L,"lintError"),a(A,"isNullish"),a(M,"mapCat")})?r.apply(t,i):r)||(e.exports=o)},4054:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[t,n(535)],void 0===(o="function"==typeof(r=function(e,t){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.l=void 0;var n=Object.defineProperty,r=(e,t)=>n(e,"name",{value:t,configurable:!0});function i(e,t){return t.forEach((function(t){t&&"string"!=typeof t&&!Array.isArray(t)&&Object.keys(t).forEach((function(n){if("default"!==n&&!(n in e)){var r=Object.getOwnPropertyDescriptor(t,n);Object.defineProperty(e,n,r.get?r:{enumerable:!0,get:function(){return t[n]}})}}))})),Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}r(i,"_mergeNamespaces");var o={exports:{}};!function(e){var t="CodeMirror-lint-markers",n="CodeMirror-lint-line-";function i(t,n,i){var o=document.createElement("div");function a(t){if(!o.parentNode)return e.off(document,"mousemove",a);o.style.top=Math.max(0,t.clientY-o.offsetHeight-5)+"px",o.style.left=t.clientX+5+"px"}return o.className="CodeMirror-lint-tooltip cm-s-"+t.options.theme,o.appendChild(i.cloneNode(!0)),t.state.lint.options.selfContain?t.getWrapperElement().appendChild(o):document.body.appendChild(o),r(a,"position"),e.on(document,"mousemove",a),a(n),null!=o.style.opacity&&(o.style.opacity=1),o}function o(e){e.parentNode&&e.parentNode.removeChild(e)}function a(e){e.parentNode&&(null==e.style.opacity&&o(e),e.style.opacity=0,setTimeout((function(){o(e)}),600))}function s(t,n,o,s){var l=i(t,n,o);function u(){e.off(s,"mouseout",u),l&&(a(l),l=null)}r(u,"hide");var c=setInterval((function(){if(l)for(var e=s;;e=e.parentNode){if(e&&11==e.nodeType&&(e=e.host),e==document.body)return;if(!e){u();break}}if(!l)return clearInterval(c)}),400);e.on(s,"mouseout",u)}function l(e,t,n){for(var r in this.marked=[],t instanceof Function&&(t={getAnnotations:t}),t&&!0!==t||(t={}),this.options={},this.linterOptions=t.options||{},u)this.options[r]=u[r];for(var r in t)u.hasOwnProperty(r)?null!=t[r]&&(this.options[r]=t[r]):t.options||(this.linterOptions[r]=t[r]);this.timeout=null,this.hasGutter=n,this.onMouseOver=function(t){T(e,t)},this.waitingFor=0}r(i,"showTooltip"),r(o,"rm"),r(a,"hideTooltip"),r(s,"showTooltipFor"),r(l,"LintState");var u={highlightLines:!1,tooltips:!0,delay:500,lintOnChange:!0,getAnnotations:null,async:!1,selfContain:null,formatAnnotation:null,onUpdateLinting:null};function c(e){var n=e.state.lint;n.hasGutter&&e.clearGutter(t),n.options.highlightLines&&d(e);for(var r=0;r-1)&&u.push(e.message)}));for(var d=null,g=i.hasGutter&&document.createDocumentFragment(),v=0;v1,o.tooltips)),o.highlightLines&&e.addLineClass(s,"wrap",n+d)}}o.onUpdateLinting&&o.onUpdateLinting(r,a,e)}}function b(e){var t=e.state.lint;t&&(clearTimeout(t.timeout),t.timeout=setTimeout((function(){v(e)}),t.options.delay))}function E(e,t,n){for(var r=n.target||n.srcElement,i=document.createDocumentFragment(),o=0;on(e,"name",{value:t,configurable:!0});function i(e,t){return t.forEach((function(t){t&&"string"!=typeof t&&!Array.isArray(t)&&Object.keys(t).forEach((function(n){if("default"!==n&&!(n in e)){var r=Object.getOwnPropertyDescriptor(t,n);Object.defineProperty(e,n,r.get?r:{enumerable:!0,get:function(){return t[n]}})}}))})),Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}r(i,"_mergeNamespaces");var o={exports:{}};e.a=o,function(e){var t=/MSIE \d/.test(navigator.userAgent)&&(null==document.documentMode||document.documentMode<8),n=e.Pos,i={"(":")>",")":"(<","[":"]>","]":"[<","{":"}>","}":"{<","<":">>",">":"<<"};function o(e){return e&&e.bracketRegex||/[(){}[\]]/}function a(e,t,r){var a=e.getLineHandle(t.line),l=t.ch-1,u=r&&r.afterCursor;null==u&&(u=/(^| )cm-fat-cursor($| )/.test(e.getWrapperElement().className));var c=o(r),d=!u&&l>=0&&c.test(a.text.charAt(l))&&i[a.text.charAt(l)]||c.test(a.text.charAt(l+1))&&i[a.text.charAt(++l)];if(!d)return null;var f=">"==d.charAt(1)?1:-1;if(r&&r.strict&&f>0!=(l==t.ch))return null;var p=e.getTokenTypeAt(n(t.line,l+1)),h=s(e,n(t.line,l+(f>0?1:0)),f,p,r);return null==h?null:{from:n(t.line,l),to:h&&h.pos,match:h&&h.ch==d.charAt(0),forward:f>0}}function s(e,t,r,a,s){for(var l=s&&s.maxScanLineLength||1e4,u=s&&s.maxScanLines||1e3,c=[],d=o(s),f=r>0?Math.min(t.line+u,e.lastLine()+1):Math.max(e.firstLine()-1,t.line-u),p=t.line;p!=f;p+=r){var h=e.getLine(p);if(h){var m=r>0?0:h.length-1,g=r>0?h.length:-1;if(!(h.length>l))for(p==t.line&&(m=t.ch-(r<0?1:0));m!=g;m+=r){var v=h.charAt(m);if(d.test(v)&&(void 0===a||(e.getTokenTypeAt(n(p,m+1))||"")==(a||""))){var y=i[v];if(y&&">"==y.charAt(1)==r>0)c.push(v);else{if(!c.length)return{pos:n(p,m),ch:v};c.pop()}}}}}return p-r!=(r>0?e.lastLine():e.firstLine())&&null}function l(e,i,o){for(var s=e.state.matchBrackets.maxHighlightLineLength||1e3,l=o&&o.highlightNonMatching,u=[],c=e.listSelections(),d=0;da((e=>{const t=(0,n.o)({eatWhitespace:e=>e.eatWhile(n.i),lexRules:n.L,parseRules:n.P,editorConfig:{tabSize:e.tabSize}});return{config:e,startState:t.startState,token:t.token,indent:r.i,electricInput:/^\s*[})\]]/,fold:"brace",lineComment:"#",closeBrackets:{pairs:'()[]{}""',explode:"()[]{}"}}}),"name",{value:"graphqlModeFactory",configurable:!0}))();e.C.defineMode("graphql",s)})?r.apply(t,i):r)||(e.exports=o)},1430:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[n(535),n(3573),n(6856),n(6592),n(9196),n(1850)],void 0===(o="function"==typeof(r=function(e,t,n,r,i,o){"use strict";e.C.defineMode("graphql-results",(e=>{const t=(0,n.o)({eatWhitespace:e=>e.eatSpace(),lexRules:a,parseRules:s,editorConfig:{tabSize:e.tabSize}});return{config:e,startState:t.startState,token:t.token,indent:r.i,electricInput:/^\s*[}\]]/,fold:"brace",closeBrackets:{pairs:'[]{}""',explode:"[]{}"}}}));const a={Punctuation:/^\[|]|\{|\}|:|,/,Number:/^-?(?:0|(?:[1-9][0-9]*))(?:\.[0-9]*)?(?:[eE][+-]?[0-9]+)?/,String:/^"(?:[^"\\]|\\(?:"|\/|\\|b|f|n|r|t|u[0-9a-fA-F]{4}))*"?/,Keyword:/^true|false|null/},s={Document:[(0,n.p)("{"),(0,n.l)("Entry",(0,n.p)(",")),(0,n.p)("}")],Entry:[(0,n.t)("String","def"),(0,n.p)(":"),"Value"],Value(e){switch(e.kind){case"Number":return"NumberValue";case"String":return"StringValue";case"Punctuation":switch(e.value){case"[":return"ListValue";case"{":return"ObjectValue"}return null;case"Keyword":switch(e.value){case"true":case"false":return"BooleanValue";case"null":return"NullValue"}return null}},NumberValue:[(0,n.t)("Number","number")],StringValue:[(0,n.t)("String","string")],BooleanValue:[(0,n.t)("Keyword","builtin")],NullValue:[(0,n.t)("Keyword","keyword")],ListValue:[(0,n.p)("["),(0,n.l)("Value",(0,n.p)(",")),(0,n.p)("]")],ObjectValue:[(0,n.p)("{"),(0,n.l)("ObjectField",(0,n.p)(",")),(0,n.p)("}")],ObjectField:[(0,n.t)("String","property"),(0,n.p)(":"),"Value"]}})?r.apply(t,i):r)||(e.exports=o)},3340:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[n(535),n(3573),n(6856),n(6592),n(9196),n(1850)],void 0===(o="function"==typeof(r=function(e,t,n,r,i,o){"use strict";var a=Object.defineProperty;e.C.defineMode("graphql-variables",(e=>{const t=(0,n.o)({eatWhitespace:e=>e.eatSpace(),lexRules:s,parseRules:l,editorConfig:{tabSize:e.tabSize}});return{config:e,startState:t.startState,token:t.token,indent:r.i,electricInput:/^\s*[}\]]/,fold:"brace",closeBrackets:{pairs:'[]{}""',explode:"[]{}"}}}));const s={Punctuation:/^\[|]|\{|\}|:|,/,Number:/^-?(?:0|(?:[1-9][0-9]*))(?:\.[0-9]*)?(?:[eE][+-]?[0-9]+)?/,String:/^"(?:[^"\\]|\\(?:"|\/|\\|b|f|n|r|t|u[0-9a-fA-F]{4}))*"?/,Keyword:/^true|false|null/},l={Document:[(0,n.p)("{"),(0,n.l)("Variable",(0,n.b)((0,n.p)(","))),(0,n.p)("}")],Variable:[u("variable"),(0,n.p)(":"),"Value"],Value(e){switch(e.kind){case"Number":return"NumberValue";case"String":return"StringValue";case"Punctuation":switch(e.value){case"[":return"ListValue";case"{":return"ObjectValue"}return null;case"Keyword":switch(e.value){case"true":case"false":return"BooleanValue";case"null":return"NullValue"}return null}},NumberValue:[(0,n.t)("Number","number")],StringValue:[(0,n.t)("String","string")],BooleanValue:[(0,n.t)("Keyword","builtin")],NullValue:[(0,n.t)("Keyword","keyword")],ListValue:[(0,n.p)("["),(0,n.l)("Value",(0,n.b)((0,n.p)(","))),(0,n.p)("]")],ObjectValue:[(0,n.p)("{"),(0,n.l)("ObjectField",(0,n.b)((0,n.p)(","))),(0,n.p)("}")],ObjectField:[u("attribute"),(0,n.p)(":"),"Value"]};function u(e){return{style:e,match:e=>"String"===e.kind,update(e,t){e.name=t.value.slice(1,-1)}}}a(u,"name",{value:"namedKey",configurable:!0})})?r.apply(t,i):r)||(e.exports=o)},9509:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[t,n(535),n(9407),n(8058)],r=function(e,t,n,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.s=void 0;var i=Object.defineProperty,o=(e,t)=>i(e,"name",{value:t,configurable:!0});function a(e,t){return t.forEach((function(t){t&&"string"!=typeof t&&!Array.isArray(t)&&Object.keys(t).forEach((function(n){if("default"!==n&&!(n in e)){var r=Object.getOwnPropertyDescriptor(t,n);Object.defineProperty(e,n,r.get?r:{enumerable:!0,get:function(){return t[n]}})}}))})),Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}o(a,"_mergeNamespaces");var s={exports:{}};!function(e){function t(e,t){return"string"==typeof e?e=new RegExp(e.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&"),t?"gi":"g"):e.global||(e=new RegExp(e.source,e.ignoreCase?"gi":"g")),{token:function(t){e.lastIndex=t.pos;var n=e.exec(t.string);if(n&&n.index==t.pos)return t.pos+=n[0].length||1,"searching";n?t.pos=n.index:t.skipToEnd()}}}function n(){this.posFrom=this.posTo=this.lastQuery=this.query=null,this.overlay=null}function r(e){return e.state.search||(e.state.search=new n)}function i(e){return"string"==typeof e&&e==e.toLowerCase()}function a(e,t,n){return e.getSearchCursor(t,n,{caseFold:i(t),multiline:!0})}function s(e,t,n,r,i){e.openDialog(t,r,{value:n,selectValueOnOpen:!0,closeOnEnter:!1,onClose:function(){m(e)},onKeyDown:i,bottom:e.options.search.bottom})}function l(e,t,n,r,i){e.openDialog?e.openDialog(t,i,{value:r,selectValueOnOpen:!0,bottom:e.options.search.bottom}):i(prompt(n,r))}function u(e,t,n,r){e.openConfirm?e.openConfirm(t,r):confirm(n)&&r[0]()}function c(e){return e.replace(/\\([nrt\\])/g,(function(e,t){return"n"==t?"\n":"r"==t?"\r":"t"==t?"\t":"\\"==t?"\\":e}))}function d(e){var t=e.match(/^\/(.*)\/([a-z]*)$/);if(t)try{e=new RegExp(t[1],-1==t[2].indexOf("i")?"":"i")}catch(e){}else e=c(e);return("string"==typeof e?""==e:e.test(""))&&(e=/x^/),e}function f(e,n,r){n.queryText=r,n.query=d(r),e.removeOverlay(n.overlay,i(n.query)),n.overlay=t(n.query,i(n.query)),e.addOverlay(n.overlay),e.showMatchesOnScrollbar&&(n.annotate&&(n.annotate.clear(),n.annotate=null),n.annotate=e.showMatchesOnScrollbar(n.query,i(n.query)))}function p(t,n,i,a){var u=r(t);if(u.query)return h(t,n);var c=t.getSelection()||u.lastQuery;if(c instanceof RegExp&&"x^"==c.source&&(c=null),i&&t.openDialog){var d=null,p=o((function(n,r){e.e_stop(r),n&&(n!=u.queryText&&(f(t,u,n),u.posFrom=u.posTo=t.getCursor()),d&&(d.style.opacity=1),h(t,r.shiftKey,(function(e,n){var r;n.line<3&&document.querySelector&&(r=t.display.wrapper.querySelector(".CodeMirror-dialog"))&&r.getBoundingClientRect().bottom-4>t.cursorCoords(n,"window").top&&((d=r).style.opacity=.4)})))}),"searchNext");s(t,v(t),c,p,(function(n,i){var o=e.keyName(n),a=t.getOption("extraKeys"),s=a&&a[o]||e.keyMap[t.getOption("keyMap")][o];"findNext"==s||"findPrev"==s||"findPersistentNext"==s||"findPersistentPrev"==s?(e.e_stop(n),f(t,r(t),i),t.execCommand(s)):"find"!=s&&"findPersistent"!=s||(e.e_stop(n),p(i,n))})),a&&c&&(f(t,u,c),h(t,n))}else l(t,v(t),"Search for:",c,(function(e){e&&!u.query&&t.operation((function(){f(t,u,e),u.posFrom=u.posTo=t.getCursor(),h(t,n)}))}))}function h(t,n,i){t.operation((function(){var o=r(t),s=a(t,o.query,n?o.posFrom:o.posTo);(s.find(n)||(s=a(t,o.query,n?e.Pos(t.lastLine()):e.Pos(t.firstLine(),0))).find(n))&&(t.setSelection(s.from(),s.to()),t.scrollIntoView({from:s.from(),to:s.to()},20),o.posFrom=s.from(),o.posTo=s.to(),i&&i(s.from(),s.to()))}))}function m(e){e.operation((function(){var t=r(e);t.lastQuery=t.query,t.query&&(t.query=t.queryText=null,e.removeOverlay(t.overlay),t.annotate&&(t.annotate.clear(),t.annotate=null))}))}function g(e,t){var n=e?document.createElement(e):document.createDocumentFragment();for(var r in t)n[r]=t[r];for(var i=2;in(e,"name",{value:t,configurable:!0});function i(e,t){return t.forEach((function(t){t&&"string"!=typeof t&&!Array.isArray(t)&&Object.keys(t).forEach((function(n){if("default"!==n&&!(n in e)){var r=Object.getOwnPropertyDescriptor(t,n);Object.defineProperty(e,n,r.get?r:{enumerable:!0,get:function(){return t[n]}})}}))})),Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}r(i,"_mergeNamespaces");var o={exports:{}};e.a=o,function(e){var t,n,i=e.Pos;function o(e){var t=e.flags;return null!=t?t:(e.ignoreCase?"i":"")+(e.global?"g":"")+(e.multiline?"m":"")}function a(e,t){for(var n=o(e),r=n,i=0;ic);d++){var f=e.getLine(u++);r=null==r?f:r+"\n"+f}o*=2,t.lastIndex=n.ch;var p=t.exec(r);if(p){var h=r.slice(0,p.index).split("\n"),m=p[0].split("\n"),g=n.line+h.length-1,v=h[h.length-1].length;return{from:i(g,v),to:i(g+m.length-1,1==m.length?v+m[0].length:m[m.length-1].length),match:p}}}}function c(e,t,n){for(var r,i=0;i<=e.length;){t.lastIndex=i;var o=t.exec(e);if(!o)break;var a=o.index+o[0].length;if(a>e.length-n)break;(!r||a>r.index+r[0].length)&&(r=o),i=o.index+1}return r}function d(e,t,n){t=a(t,"g");for(var r=n.line,o=n.ch,s=e.firstLine();r>=s;r--,o=-1){var l=e.getLine(r),u=c(l,t,o<0?0:l.length-o);if(u)return{from:i(r,u.index),to:i(r,u.index+u[0].length),match:u}}}function f(e,t,n){if(!s(t))return d(e,t,n);t=a(t,"gm");for(var r,o=1,l=e.getLine(n.line).length-n.ch,u=n.line,f=e.firstLine();u>=f;){for(var p=0;p=f;p++){var h=e.getLine(u--);r=null==r?h:h+"\n"+r}o*=2;var m=c(r,t,l);if(m){var g=r.slice(0,m.index).split("\n"),v=m[0].split("\n"),y=u+g.length,b=g[g.length-1].length;return{from:i(y,b),to:i(y+v.length-1,1==v.length?b+v[0].length:v[v.length-1].length),match:m}}}}function p(e,t,n,r){if(e.length==t.length)return n;for(var i=0,o=n+Math.max(0,e.length-t.length);;){if(i==o)return i;var a=i+o>>1,s=r(e.slice(0,a)).length;if(s==n)return a;s>n?o=a:i=a+1}}function h(e,r,o,a){if(!r.length)return null;var s=a?t:n,l=s(r).split(/\r|\n\r?/);e:for(var u=o.line,c=o.ch,d=e.lastLine()+1-l.length;u<=d;u++,c=0){var f=e.getLine(u).slice(c),h=s(f);if(1==l.length){var m=h.indexOf(l[0]);if(-1==m)continue e;return o=p(f,h,m,s)+c,{from:i(u,p(f,h,m,s)+c),to:i(u,p(f,h,m+l[0].length,s)+c)}}var g=h.length-l[0].length;if(h.slice(g)==l[0]){for(var v=1;v=d;u--,c=-1){var f=e.getLine(u);c>-1&&(f=f.slice(0,c));var h=s(f);if(1==l.length){var m=h.lastIndexOf(l[0]);if(-1==m)continue e;return{from:i(u,p(f,h,m,s)),to:i(u,p(f,h,m+l[0].length,s))}}var g=l[l.length-1];if(h.slice(0,g.length)==g){var v=1;for(o=u-l.length+1;v(this.doc.getLine(n.line)||"").length&&(n.ch=0,n.line++)),0!=e.cmpPos(n,this.doc.clipPos(n))))return this.atOccurrence=!1;var r=this.matches(t,n);if(this.afterEmptyMatch=r&&0==e.cmpPos(r.from,r.to),r)return this.pos=r,this.atOccurrence=!0,this.pos.match||!0;var o=i(t?this.doc.firstLine():this.doc.lastLine()+1,0);return this.pos={from:o,to:o},this.atOccurrence=!1},from:function(){if(this.atOccurrence)return this.pos.from},to:function(){if(this.atOccurrence)return this.pos.to},replace:function(t,n){if(this.atOccurrence){var r=e.splitLines(t);this.doc.replaceRange(r,this.pos.from,this.pos.to,n),this.pos.to=i(this.pos.from.line+r.length-1,r[r.length-1].length+(1==r.length?this.pos.from.ch:0))}}},e.defineExtension("getSearchCursor",(function(e,t,n){return new g(this.doc,e,t,n)})),e.defineDocExtension("getSearchCursor",(function(e,t,n){return new g(this,e,t,n)})),e.defineExtension("selectMatches",(function(t,n){for(var r=[],i=this.getSearchCursor(t,this.getCursor("from"),n);i.findNext()&&!(e.cmpPos(i.to(),this.getCursor("to"))>0);)r.push({anchor:i.from(),head:i.to()});r.length&&this.setSelections(r,0)}))}(t.a.exports);var a=i({__proto__:null,default:o.exports},[o.exports]);e.s=a})?r.apply(t,i):r)||(e.exports=o)},6980:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[t,n(535)],void 0===(o="function"==typeof(r=function(e,t){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.s=void 0;var n=Object.defineProperty,r=(e,t)=>n(e,"name",{value:t,configurable:!0});function i(e,t){return t.forEach((function(t){t&&"string"!=typeof t&&!Array.isArray(t)&&Object.keys(t).forEach((function(n){if("default"!==n&&!(n in e)){var r=Object.getOwnPropertyDescriptor(t,n);Object.defineProperty(e,n,r.get?r:{enumerable:!0,get:function(){return t[n]}})}}))})),Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}r(i,"_mergeNamespaces");var o={exports:{}};!function(e){var t="CodeMirror-hint",n="CodeMirror-hint-active";function i(e,t){if(this.cm=e,this.options=t,this.widget=null,this.debounce=0,this.tick=0,this.startPos=this.cm.getCursor("start"),this.startLen=this.cm.getLine(this.startPos.line).length-this.cm.getSelection().length,this.options.updateOnCursorActivity){var n=this;e.on("cursorActivity",this.activityFunc=function(){n.cursorActivity()})}}e.showHint=function(e,t,n){if(!t)return e.showHint(n);n&&n.async&&(t.async=!0);var r={hint:t};if(n)for(var i in n)r[i]=n[i];return e.showHint(r)},e.defineExtension("showHint",(function(t){t=s(this,this.getCursor("start"),t);var n=this.listSelections();if(!(n.length>1)){if(this.somethingSelected()){if(!t.hint.supportsSelection)return;for(var r=0;rf.clientHeight+1;if(setTimeout((function(){D=a.getScrollInfo()})),L.bottom-I>0){var M=L.bottom-L.top;if(E.top-(E.bottom-L.top)-M>0)f.style.top=(w=E.top-M-x)+"px",C=!1;else if(M>I){f.style.height=I-5+"px",f.style.top=(w=E.bottom-L.top-x)+"px";var R=a.getCursor();i.from.ch!=R.ch&&(E=a.cursorCoords(R),f.style.left=(T=E.left-S)+"px",L=f.getBoundingClientRect())}}var F,P=L.right-O;if(A&&(P+=a.display.nativeBarWidth),P>0&&(L.right-L.left>O&&(f.style.width=O-5+"px",P-=L.right-L.left-O),f.style.left=(T=E.left-P-S)+"px"),A)for(var j=f.firstChild;j;j=j.nextSibling)j.style.paddingRight=a.display.nativeBarWidth+"px";a.addKeyMap(this.keyMap=u(r,{moveFocus:function(e,t){o.changeActive(o.selectedHint+e,t)},setFocus:function(e){o.changeActive(e)},menuSize:function(){return o.screenAmount()},length:h.length,close:function(){r.close()},pick:function(){o.pick()},data:i})),r.options.closeOnUnfocus&&(a.on("blur",this.onBlur=function(){F=setTimeout((function(){r.close()}),100)}),a.on("focus",this.onFocus=function(){clearTimeout(F)})),a.on("scroll",this.onScroll=function(){var e=a.getScrollInfo(),t=a.getWrapperElement().getBoundingClientRect();D||(D=a.getScrollInfo());var n=w+D.top-e.top,i=n-(d.pageYOffset||(s.documentElement||s.body).scrollTop);if(C||(i+=f.offsetHeight),i<=t.top||i>=t.bottom)return r.close();f.style.top=n+"px",f.style.left=T+D.left-e.left+"px"}),e.on(f,"dblclick",(function(e){var t=c(f,e.target||e.srcElement);t&&null!=t.hintId&&(o.changeActive(t.hintId),o.pick())})),e.on(f,"click",(function(e){var t=c(f,e.target||e.srcElement);t&&null!=t.hintId&&(o.changeActive(t.hintId),r.options.completeOnSingleClick&&o.pick())})),e.on(f,"mousedown",(function(){setTimeout((function(){a.focus()}),20)}));var V=this.getSelectedHintRange();return 0===V.from&&0===V.to||this.scrollToActive(),e.signal(i,"select",h[this.selectedHint],f.childNodes[this.selectedHint]),!0}function f(e,t){if(!e.somethingSelected())return t;for(var n=[],r=0;r0?t(e):a(r+1)}))}r(a,"run"),a(0)}),"resolved");return a.async=!0,a.supportsSelection=!0,a}return(i=t.getHelper(t.getCursor(),"hintWords"))?function(t){return e.hint.fromList(t,{words:i})}:e.hint.anyword?function(t,n){return e.hint.anyword(t,n)}:function(){}}i.prototype={close:function(){this.active()&&(this.cm.state.completionActive=null,this.tick=null,this.options.updateOnCursorActivity&&this.cm.off("cursorActivity",this.activityFunc),this.widget&&this.data&&e.signal(this.data,"close"),this.widget&&this.widget.close(),e.signal(this.cm,"endCompletion",this.cm))},active:function(){return this.cm.state.completionActive==this},pick:function(t,n){var r=t.list[n],i=this;this.cm.operation((function(){r.hint?r.hint(i.cm,t,r):i.cm.replaceRange(l(r),r.from||t.from,r.to||t.to,"complete"),e.signal(t,"pick",r),i.cm.scrollIntoView()})),this.options.closeOnPick&&this.close()},cursorActivity:function(){this.debounce&&(a(this.debounce),this.debounce=0);var e=this.startPos;this.data&&(e=this.data.from);var t=this.cm.getCursor(),n=this.cm.getLine(t.line);if(t.line!=this.startPos.line||n.length-t.ch!=this.startLen-this.startPos.ch||t.ch=this.data.list.length?t=r?this.data.list.length-1:0:t<0&&(t=r?0:this.data.list.length-1),this.selectedHint!=t){var i=this.hints.childNodes[this.selectedHint];i&&(i.className=i.className.replace(" "+n,""),i.removeAttribute("aria-selected")),(i=this.hints.childNodes[this.selectedHint=t]).className+=" "+n,i.setAttribute("aria-selected","true"),this.completion.cm.getInputField().setAttribute("aria-activedescendant",i.id),this.scrollToActive(),e.signal(this.data,"select",this.data.list[this.selectedHint],i)}},scrollToActive:function(){var e=this.getSelectedHintRange(),t=this.hints.childNodes[e.from],n=this.hints.childNodes[e.to],r=this.hints.firstChild;t.offsetTopthis.hints.scrollTop+this.hints.clientHeight&&(this.hints.scrollTop=n.offsetTop+n.offsetHeight-this.hints.clientHeight+r.offsetTop)},screenAmount:function(){return Math.floor(this.hints.clientHeight/this.hints.firstChild.offsetHeight)||1},getSelectedHintRange:function(){var e=this.completion.options.scrollMargin||0;return{from:Math.max(0,this.selectedHint-e),to:Math.min(this.data.list.length-1,this.selectedHint+e)}}},r(f,"applicableHelpers"),r(p,"fetchHints"),r(h,"resolveAutoHints"),e.registerHelper("hint","auto",{resolve:h}),e.registerHelper("hint","fromList",(function(t,n){var r,i=t.getCursor(),o=t.getTokenAt(i),a=e.Pos(i.line,o.start),s=i;o.start,]/,closeOnPick:!0,closeOnUnfocus:!0,updateOnCursorActivity:!0,completeOnSingleClick:!0,container:null,customKeys:null,extraKeys:null,paddingForScrollbar:!0,moveOnOverlap:!0};e.defineOption("hintOptions",null)}(t.a.exports);var a=i({__proto__:null,default:o.exports},[o.exports]);e.s=a})?r.apply(t,i):r)||(e.exports=o)},2568:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[t,n(535),n(9407),n(9171)],void 0===(o="function"==typeof(r=function(e,t,n,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.s=void 0;var i=Object.defineProperty,o=(e,t)=>i(e,"name",{value:t,configurable:!0});function a(e,t){return t.forEach((function(t){t&&"string"!=typeof t&&!Array.isArray(t)&&Object.keys(t).forEach((function(n){if("default"!==n&&!(n in e)){var r=Object.getOwnPropertyDescriptor(t,n);Object.defineProperty(e,n,r.get?r:{enumerable:!0,get:function(){return t[n]}})}}))})),Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}o(a,"_mergeNamespaces");var s={exports:{}};!function(e){var t=e.commands,n=e.Pos;function r(t,r,i){if(i<0&&0==r.ch)return t.clipPos(n(r.line-1));var o=t.getLine(r.line);if(i>0&&r.ch>=o.length)return t.clipPos(n(r.line+1,0));for(var a,s="start",l=r.ch,u=l,c=i<0?0:o.length,d=0;u!=c;u+=i,d++){var f=o.charAt(i<0?u-1:u),p="_"!=f&&e.isWordChar(f)?"w":"o";if("w"==p&&f.toUpperCase()==f&&(p="W"),"start"==s)"o"!=p?(s="in",a=p):l=u+i;else if("in"==s&&a!=p){if("w"==a&&"W"==p&&i<0&&u--,"W"==a&&"w"==p&&i>0){if(u==l+1){a="w";continue}u--}break}}return n(r.line,u)}function i(e,t){e.extendSelectionsBy((function(n){return e.display.shift||e.doc.extend||n.empty()?r(e.doc,n.head,t):t<0?n.from():n.to()}))}function a(t,r){if(t.isReadOnly())return e.Pass;t.operation((function(){for(var e=t.listSelections().length,i=[],o=-1,a=0;a=n&&e.execCommand("goLineUp")}e.scrollTo(null,t.top-e.defaultTextHeight())},t.scrollLineDown=function(e){var t=e.getScrollInfo();if(!e.somethingSelected()){var n=e.lineAtHeight(t.top,"local")+1;e.getCursor().line<=n&&e.execCommand("goLineDown")}e.scrollTo(null,t.top+e.defaultTextHeight())},t.splitSelectionByLine=function(e){for(var t=e.listSelections(),r=[],i=0;io.line&&s==a.line&&0==a.ch||r.push({anchor:s==o.line?o:n(s,0),head:s==a.line?a:n(s)});e.setSelections(r,0)},t.singleSelectionTop=function(e){var t=e.listSelections()[0];e.setSelection(t.anchor,t.head,{scroll:!1})},t.selectLine=function(e){for(var t=e.listSelections(),r=[],i=0;i=0;a--){var u=r[i[a]];if(!(l&&e.cmpPos(u.head,l)>0)){var c=s(t,u.head);l=c.from,t.replaceRange(n(c.word),c.from,c.to)}}}))}function m(t){var n=t.getCursor("from"),r=t.getCursor("to");if(0==e.cmpPos(n,r)){var i=s(t,n);if(!i.word)return;n=i.from,r=i.to}return{from:n,to:r,query:t.getRange(n,r),word:i}}function g(e,t){var r=m(e);if(r){var i=r.query,o=e.getSearchCursor(i,t?r.to:r.from);(t?o.findNext():o.findPrevious())?e.setSelection(o.from(),o.to()):(o=e.getSearchCursor(i,t?n(e.firstLine(),0):e.clipPos(n(e.lastLine()))),(t?o.findNext():o.findPrevious())?e.setSelection(o.from(),o.to()):r.word&&e.setSelection(r.from,r.to))}}o(d,"selectBetweenBrackets"),t.selectScope=function(e){d(e)||e.execCommand("selectAll")},t.selectBetweenBrackets=function(t){if(!d(t))return e.Pass},o(f,"puncType"),t.goToBracket=function(t){t.extendSelectionsBy((function(r){var i=t.scanForBracket(r.head,1,f(t.getTokenTypeAt(r.head)));if(i&&0!=e.cmpPos(i.pos,r.head))return i.pos;var o=t.scanForBracket(r.head,-1,f(t.getTokenTypeAt(n(r.head.line,r.head.ch+1))));return o&&n(o.pos.line,o.pos.ch+1)||r.head}))},t.swapLineUp=function(t){if(t.isReadOnly())return e.Pass;for(var r=t.listSelections(),i=[],o=t.firstLine()-1,a=[],s=0;so?i.push(u,c):i.length&&(i[i.length-1]=c),o=c}t.operation((function(){for(var e=0;et.lastLine()?t.replaceRange("\n"+s,n(t.lastLine()),null,"+swapLine"):t.replaceRange(s+"\n",n(o,0),null,"+swapLine")}t.setSelections(a),t.scrollIntoView()}))},t.swapLineDown=function(t){if(t.isReadOnly())return e.Pass;for(var r=t.listSelections(),i=[],o=t.lastLine()+1,a=r.length-1;a>=0;a--){var s=r[a],l=s.to().line+1,u=s.from().line;0!=s.to().ch||s.empty()||l--,l=0;e-=2){var r=i[e],o=i[e+1],a=t.getLine(r);r==t.lastLine()?t.replaceRange("",n(r-1),n(r),"+swapLine"):t.replaceRange("",n(r,0),n(r+1,0),"+swapLine"),t.replaceRange(a+"\n",n(o,0),null,"+swapLine")}t.scrollIntoView()}))},t.toggleCommentIndented=function(e){e.toggleComment({indent:!0})},t.joinLines=function(e){for(var t=e.listSelections(),r=[],i=0;i=0;o--){var a=r[o].head,s=t.getRange({line:a.line,ch:0},a),l=e.countColumn(s,null,t.getOption("tabSize")),u=t.findPosH(a,-1,"char",!1);if(s&&!/\S/.test(s)&&l%i==0){var c=new n(a.line,e.findColumn(s,l-i,i));c.ch!=a.ch&&(u=c)}t.replaceRange("",u,a,"+delete")}}))},t.delLineRight=function(e){e.operation((function(){for(var t=e.listSelections(),r=t.length-1;r>=0;r--)e.replaceRange("",t[r].anchor,n(t[r].to().line),"+delete");e.scrollIntoView()}))},t.upcaseAtCursor=function(e){h(e,(function(e){return e.toUpperCase()}))},t.downcaseAtCursor=function(e){h(e,(function(e){return e.toLowerCase()}))},t.setSublimeMark=function(e){e.state.sublimeMark&&e.state.sublimeMark.clear(),e.state.sublimeMark=e.setBookmark(e.getCursor())},t.selectToSublimeMark=function(e){var t=e.state.sublimeMark&&e.state.sublimeMark.find();t&&e.setSelection(e.getCursor(),t)},t.deleteToSublimeMark=function(t){var n=t.state.sublimeMark&&t.state.sublimeMark.find();if(n){var r=t.getCursor(),i=n;if(e.cmpPos(r,i)>0){var o=i;i=r,r=o}t.state.sublimeKilled=t.getRange(r,i),t.replaceRange("",r,i)}},t.swapWithSublimeMark=function(e){var t=e.state.sublimeMark&&e.state.sublimeMark.find();t&&(e.state.sublimeMark.clear(),e.state.sublimeMark=e.setBookmark(e.getCursor()),e.setCursor(t))},t.sublimeYank=function(e){null!=e.state.sublimeKilled&&e.replaceSelection(e.state.sublimeKilled,null,"paste")},t.showInCenter=function(e){var t=e.cursorCoords(null,"local");e.scrollTo(null,(t.top+t.bottom)/2-e.getScrollInfo().clientHeight/2)},o(m,"getTarget"),o(g,"findAndGoTo"),t.findUnder=function(e){g(e,!0)},t.findUnderPrevious=function(e){g(e,!1)},t.findAllUnder=function(e){var t=m(e);if(t){for(var n=e.getSearchCursor(t.query),r=[],i=-1;n.findNext();)r.push({anchor:n.from(),head:n.to()}),n.from().line<=t.from.line&&n.from().ch<=t.from.ch&&i++;e.setSelections(r,i)}};var v=e.keyMap;v.macSublime={"Cmd-Left":"goLineStartSmart","Shift-Tab":"indentLess","Shift-Ctrl-K":"deleteLine","Alt-Q":"wrapLines","Ctrl-Left":"goSubwordLeft","Ctrl-Right":"goSubwordRight","Ctrl-Alt-Up":"scrollLineUp","Ctrl-Alt-Down":"scrollLineDown","Cmd-L":"selectLine","Shift-Cmd-L":"splitSelectionByLine",Esc:"singleSelectionTop","Cmd-Enter":"insertLineAfter","Shift-Cmd-Enter":"insertLineBefore","Cmd-D":"selectNextOccurrence","Shift-Cmd-Space":"selectScope","Shift-Cmd-M":"selectBetweenBrackets","Cmd-M":"goToBracket","Cmd-Ctrl-Up":"swapLineUp","Cmd-Ctrl-Down":"swapLineDown","Cmd-/":"toggleCommentIndented","Cmd-J":"joinLines","Shift-Cmd-D":"duplicateLine",F5:"sortLines","Shift-F5":"reverseSortLines","Cmd-F5":"sortLinesInsensitive","Shift-Cmd-F5":"reverseSortLinesInsensitive",F2:"nextBookmark","Shift-F2":"prevBookmark","Cmd-F2":"toggleBookmark","Shift-Cmd-F2":"clearBookmarks","Alt-F2":"selectBookmarks",Backspace:"smartBackspace","Cmd-K Cmd-D":"skipAndSelectNextOccurrence","Cmd-K Cmd-K":"delLineRight","Cmd-K Cmd-U":"upcaseAtCursor","Cmd-K Cmd-L":"downcaseAtCursor","Cmd-K Cmd-Space":"setSublimeMark","Cmd-K Cmd-A":"selectToSublimeMark","Cmd-K Cmd-W":"deleteToSublimeMark","Cmd-K Cmd-X":"swapWithSublimeMark","Cmd-K Cmd-Y":"sublimeYank","Cmd-K Cmd-C":"showInCenter","Cmd-K Cmd-G":"clearBookmarks","Cmd-K Cmd-Backspace":"delLineLeft","Cmd-K Cmd-1":"foldAll","Cmd-K Cmd-0":"unfoldAll","Cmd-K Cmd-J":"unfoldAll","Ctrl-Shift-Up":"addCursorToPrevLine","Ctrl-Shift-Down":"addCursorToNextLine","Cmd-F3":"findUnder","Shift-Cmd-F3":"findUnderPrevious","Alt-F3":"findAllUnder","Shift-Cmd-[":"fold","Shift-Cmd-]":"unfold","Cmd-I":"findIncremental","Shift-Cmd-I":"findIncrementalReverse","Cmd-H":"replace",F3:"findNext","Shift-F3":"findPrev",fallthrough:"macDefault"},e.normalizeKeyMap(v.macSublime),v.pcSublime={"Shift-Tab":"indentLess","Shift-Ctrl-K":"deleteLine","Alt-Q":"wrapLines","Ctrl-T":"transposeChars","Alt-Left":"goSubwordLeft","Alt-Right":"goSubwordRight","Ctrl-Up":"scrollLineUp","Ctrl-Down":"scrollLineDown","Ctrl-L":"selectLine","Shift-Ctrl-L":"splitSelectionByLine",Esc:"singleSelectionTop","Ctrl-Enter":"insertLineAfter","Shift-Ctrl-Enter":"insertLineBefore","Ctrl-D":"selectNextOccurrence","Shift-Ctrl-Space":"selectScope","Shift-Ctrl-M":"selectBetweenBrackets","Ctrl-M":"goToBracket","Shift-Ctrl-Up":"swapLineUp","Shift-Ctrl-Down":"swapLineDown","Ctrl-/":"toggleCommentIndented","Ctrl-J":"joinLines","Shift-Ctrl-D":"duplicateLine",F9:"sortLines","Shift-F9":"reverseSortLines","Ctrl-F9":"sortLinesInsensitive","Shift-Ctrl-F9":"reverseSortLinesInsensitive",F2:"nextBookmark","Shift-F2":"prevBookmark","Ctrl-F2":"toggleBookmark","Shift-Ctrl-F2":"clearBookmarks","Alt-F2":"selectBookmarks",Backspace:"smartBackspace","Ctrl-K Ctrl-D":"skipAndSelectNextOccurrence","Ctrl-K Ctrl-K":"delLineRight","Ctrl-K Ctrl-U":"upcaseAtCursor","Ctrl-K Ctrl-L":"downcaseAtCursor","Ctrl-K Ctrl-Space":"setSublimeMark","Ctrl-K Ctrl-A":"selectToSublimeMark","Ctrl-K Ctrl-W":"deleteToSublimeMark","Ctrl-K Ctrl-X":"swapWithSublimeMark","Ctrl-K Ctrl-Y":"sublimeYank","Ctrl-K Ctrl-C":"showInCenter","Ctrl-K Ctrl-G":"clearBookmarks","Ctrl-K Ctrl-Backspace":"delLineLeft","Ctrl-K Ctrl-1":"foldAll","Ctrl-K Ctrl-0":"unfoldAll","Ctrl-K Ctrl-J":"unfoldAll","Ctrl-Alt-Up":"addCursorToPrevLine","Ctrl-Alt-Down":"addCursorToNextLine","Ctrl-F3":"findUnder","Shift-Ctrl-F3":"findUnderPrevious","Alt-F3":"findAllUnder","Shift-Ctrl-[":"fold","Shift-Ctrl-]":"unfold","Ctrl-I":"findIncremental","Shift-Ctrl-I":"findIncrementalReverse","Ctrl-H":"replace",F3:"findNext","Shift-F3":"findPrev",fallthrough:"pcDefault"},e.normalizeKeyMap(v.pcSublime);var y=v.default==v.macDefault;v.sublime=y?v.macSublime:v.pcSublime}(t.a.exports,n.a.exports,r.a.exports);var l=a({__proto__:null,default:s.exports},[s.exports]);e.s=l})?r.apply(t,i):r)||(e.exports=o)},3691:function(e,t){var n,r;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,void 0===(r="function"==typeof(n=function(e){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.fetcherReturnToPromise=function(e){return t(this,void 0,void 0,(function*(){const i=yield e;return r(i)?function(e){var n;return t(this,void 0,void 0,(function*(){const t=null===(n=("return"in e?e:e[Symbol.asyncIterator]()).return)||void 0===n?void 0:n.bind(e),r=("next"in e?e:e[Symbol.asyncIterator]()).next.bind(e),i=yield r();return null==t||t(),i.value}))}(i):n(i)?(o=i,new Promise(((e,t)=>{const n=o.subscribe({next:t=>{e(t),n.unsubscribe()},error:t,complete:()=>{t(new Error("no value resolved"))}})}))):i;var o}))},e.isAsyncIterable=r,e.isObservable=n,e.isPromise=function(e){return"object"==typeof e&&null!==e&&"function"==typeof e.then};var t=function(e,t,n,r){return new(n||(n=Promise))((function(i,o){function a(e){try{l(r.next(e))}catch(e){o(e)}}function s(e){try{l(r.throw(e))}catch(e){o(e)}}function l(e){var t;e.done?i(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(a,s)}l((r=r.apply(e,t||[])).next())}))};function n(e){return"object"==typeof e&&null!==e&&"subscribe"in e&&"function"==typeof e.subscribe}function r(e){return"object"==typeof e&&null!==e&&("AsyncGenerator"===e[Symbol.toStringTag]||Symbol.asyncIterator in e)}})?n.apply(t,[t]):n)||(e.exports=r)},5454:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[t,n(2501)],void 0===(o="function"==typeof(r=function(e,t){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.createGraphiQLFetcher=function(e){let n;if("undefined"!=typeof window&&window.fetch&&(n=window.fetch),null!==(null==e?void 0:e.enableIncrementalDelivery)&&!1===e.enableIncrementalDelivery||(e.enableIncrementalDelivery=!0),e.fetch&&(n=e.fetch),!n)throw new Error("No valid fetcher implementation available");const r=(0,t.createSimpleFetcher)(e,n),i=e.enableIncrementalDelivery?(0,t.createMultipartFetcher)(e,n):r;return(n,o)=>{if("IntrospectionQuery"===n.operationName)return(e.schemaFetcher||r)(n,o);if((null==o?void 0:o.documentAST)&&(0,t.isSubscriptionWithName)(o.documentAST,n.operationName||void 0)){const r=(0,t.getWsFetcher)(e,o);if(!r)throw new Error("Your GraphiQL createFetcher is not properly configured for websocket subscriptions yet. "+(e.subscriptionUrl?`Provided URL ${e.subscriptionUrl} failed`:"Please provide subscriptionUrl, wsClient or legacyClient option first."));return r(n)}return i(n,o)}}})?r.apply(t,i):r)||(e.exports=o)},1799:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[t,n(3080),n(5454)],void 0===(o="function"==typeof(r=function(e,t,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r={createGraphiQLFetcher:!0};Object.defineProperty(e,"createGraphiQLFetcher",{enumerable:!0,get:function(){return n.createGraphiQLFetcher}}),Object.keys(t).forEach((function(n){"default"!==n&&"__esModule"!==n&&(Object.prototype.hasOwnProperty.call(r,n)||n in e&&e[n]===t[n]||Object.defineProperty(e,n,{enumerable:!0,get:function(){return t[n]}}))}))})?r.apply(t,i):r)||(e.exports=o)},2501:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[t,n(3573),n(8488),n(8042)],r=function(e,t,r,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.isSubscriptionWithName=e.getWsFetcher=e.createWebsocketsFetcherFromUrl=e.createWebsocketsFetcherFromClient=e.createSimpleFetcher=e.createMultipartFetcher=e.createLegacyWebsocketsFetcher=void 0;var o=function(e,t,n,r){return new(n||(n=Promise))((function(i,o){function a(e){try{l(r.next(e))}catch(e){o(e)}}function s(e){try{l(r.throw(e))}catch(e){o(e)}}function l(e){var t;e.done?i(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(a,s)}l((r=r.apply(e,t||[])).next())}))},a=function(e){return this instanceof a?(this.v=e,this):new a(e)},s=function(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t,n=e[Symbol.asyncIterator];return n?n.call(e):(e="function"==typeof __values?__values(e):e[Symbol.iterator](),t={},r("next"),r("throw"),r("return"),t[Symbol.asyncIterator]=function(){return this},t);function r(n){t[n]=e[n]&&function(t){return new Promise((function(r,i){!function(e,t,n,r){Promise.resolve(r).then((function(t){e({value:t,done:n})}),t)}(r,i,(t=e[n](t)).done,t.value)}))}}},l=function(e,t,n){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var r,i=n.apply(e,t||[]),o=[];return r={},s("next"),s("throw"),s("return"),r[Symbol.asyncIterator]=function(){return this},r;function s(e){i[e]&&(r[e]=function(t){return new Promise((function(n,r){o.push([e,t,n,r])>1||l(e,t)}))})}function l(e,t){try{(n=i[e](t)).value instanceof a?Promise.resolve(n.value.v).then(u,c):d(o[0][2],n)}catch(e){d(o[0][3],e)}var n}function u(e){l("next",e)}function c(e){l("throw",e)}function d(e,t){e(t),o.shift(),o.length&&l(o[0][0],o[0][1])}};e.isSubscriptionWithName=(e,n)=>{let r=!1;return(0,t.visit)(e,{OperationDefinition(e){var t;n===(null===(t=e.name)||void 0===t?void 0:t.value)&&"subscription"===e.operation&&(r=!0)}}),r};e.createSimpleFetcher=(e,t)=>(n,r)=>o(void 0,void 0,void 0,(function*(){return(yield t(e.url,{method:"POST",body:JSON.stringify(n),headers:Object.assign(Object.assign({"content-type":"application/json"},e.headers),null==r?void 0:r.headers)})).json()}));const u=(e,t)=>{let r;try{const{createClient:i}=n(7674);return r=i({url:e,connectionParams:t}),c(r)}catch(t){if((e=>"object"==typeof e&&null!==e&&"code"in e)(t)&&"MODULE_NOT_FOUND"===t.code)throw new Error("You need to install the 'graphql-ws' package to use websockets when passing a 'subscriptionUrl'");console.error(`Error creating websocket client for ${e}`,t)}};e.createWebsocketsFetcherFromUrl=u;const c=e=>t=>(0,i.makeAsyncIterableIteratorFromSink)((n=>e.subscribe(t,Object.assign(Object.assign({},n),{error:e=>{e instanceof CloseEvent?n.error(new Error(`Socket closed with event ${e.code} ${e.reason||""}`.trim())):n.error(e)}}))));e.createWebsocketsFetcherFromClient=c;const d=e=>t=>{const n=e.request(t);return(0,i.makeAsyncIterableIteratorFromSink)((e=>n.subscribe(e).unsubscribe))};e.createLegacyWebsocketsFetcher=d;e.createMultipartFetcher=(e,t)=>function(n,o){return l(this,arguments,(function*(){var l,u;const c=yield a(t(e.url,{method:"POST",body:JSON.stringify(n),headers:Object.assign(Object.assign({"content-type":"application/json",accept:"application/json, multipart/mixed"},e.headers),null==o?void 0:o.headers)}).then((e=>(0,r.meros)(e,{multiple:!0}))));if(!(0,i.isAsyncIterable)(c))return yield a(yield yield a(c.json()));try{for(var d,f=s(c);!(d=yield a(f.next())).done;){const e=d.value;if(e.some((e=>!e.json))){const t=e.map((e=>`Headers::\n${e.headers}\n\nBody::\n${e.body}`));throw new Error(`Expected multipart chunks to be of json type. got:\n${t}`)}yield yield a(e.map((e=>e.body)))}}catch(e){l={error:e}}finally{try{d&&!d.done&&(u=f.return)&&(yield a(u.call(f)))}finally{if(l)throw l.error}}}))};e.getWsFetcher=(e,t)=>{if(e.wsClient)return c(e.wsClient);if(e.subscriptionUrl)return u(e.subscriptionUrl,Object.assign(Object.assign({},e.wsConnectionParams),null==t?void 0:t.headers));const n=e.legacyClient||e.legacyWsClient;return n?d(n):void 0}},void 0===(o=r.apply(t,i))||(e.exports=o)},3080:function(e,t){var n,r;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,void 0===(r="function"==typeof(n=function(e){"use strict";Object.defineProperty(e,"__esModule",{value:!0})})?n.apply(t,[t]):n)||(e.exports=r)},4574:function(e,t){var n,r;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,void 0===(r="function"==typeof(n=function(e){"use strict";function t(e){return JSON.stringify(e,null,2)}function n(e){return e instanceof Error?function(e){return Object.assign(Object.assign({},e),{message:e.message,stack:e.stack})}(e):e}Object.defineProperty(e,"__esModule",{value:!0}),e.formatError=function(e){return Array.isArray(e)?t({errors:e.map((e=>n(e)))}):t({errors:[n(e)]})},e.formatResult=function(e){return t(e)}})?n.apply(t,[t]):n)||(e.exports=r)},3738:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[t,n(3573)],void 0===(o="function"==typeof(r=function(e,t){"use strict";function n(e){if(!("getFields"in e))return[];const n=e.getFields();if(n.id)return["id"];if(n.edges)return["edges"];if(n.node)return["node"];const r=[];for(const e of Object.keys(n))(0,t.isLeafType)(n[e].type)&&r.push(e);return r}function r(e,n){const i=(0,t.getNamedType)(e);if(!e||(0,t.isLeafType)(e))return;const o=n(i);return Array.isArray(o)&&0!==o.length&&"getFields"in i?{kind:t.Kind.SELECTION_SET,selections:o.map((e=>{const o=i.getFields()[e],a=o?o.type:null;return{kind:t.Kind.FIELD,name:{kind:t.Kind.NAME,value:e},selectionSet:r(a,n)}}))}:void 0}function i(e,t){if(0===t.length)return e;let n="",r=0;for(const{index:i,string:o}of t)n+=e.slice(r,i)+o,r=i;return n+=e.slice(r),n}Object.defineProperty(e,"__esModule",{value:!0}),e.fillLeafs=function(e,o,a){const s=[];if(!e||!o)return{insertions:s,result:o};let l;try{l=(0,t.parse)(o)}catch(e){return{insertions:s,result:o}}const u=a||n,c=new t.TypeInfo(e);return(0,t.visit)(l,{leave(e){c.leave(e)},enter(e){if(c.enter(e),"Field"===e.kind&&!e.selectionSet){const n=r(function(e){if(e)return e}(c.getType()),u);if(n&&e.loc){const r=function(e,t){let n=t,r=t;for(;n;){const t=e.charCodeAt(n-1);if(10===t||13===t||8232===t||8233===t)break;n--,9!==t&&11!==t&&12!==t&&32!==t&&160!==t&&(r=n)}return e.slice(n,r)}(o,e.loc.start);s.push({index:e.loc.end,string:" "+(0,t.print)(n).replaceAll("\n","\n"+r)})}}}}),{insertions:s,result:i(o,s)}}})?r.apply(t,i):r)||(e.exports=o)},7293:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[t,n(3738),n(5682),n(1312)],void 0===(o="function"==typeof(r=function(e,t,n,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),Object.keys(t).forEach((function(n){"default"!==n&&"__esModule"!==n&&(n in e&&e[n]===t[n]||Object.defineProperty(e,n,{enumerable:!0,get:function(){return t[n]}}))})),Object.keys(n).forEach((function(t){"default"!==t&&"__esModule"!==t&&(t in e&&e[t]===n[t]||Object.defineProperty(e,t,{enumerable:!0,get:function(){return n[t]}}))})),Object.keys(r).forEach((function(t){"default"!==t&&"__esModule"!==t&&(t in e&&e[t]===r[t]||Object.defineProperty(e,t,{enumerable:!0,get:function(){return r[t]}}))}))})?r.apply(t,i):r)||(e.exports=o)},5682:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[t,n(3573)],void 0===(o="function"==typeof(r=function(e,t){"use strict";function n(e,r,i){var o;const a=i?(0,t.getNamedType)(i).name:null,s=[],l=[];for(let u of r){if("FragmentSpread"===u.kind){const n=u.name.value;if(!u.directives||0===u.directives.length){if(l.includes(n))continue;l.push(n)}const r=e[u.name.value];if(r){const{typeCondition:e,directives:n,selectionSet:i}=r;u={kind:t.Kind.INLINE_FRAGMENT,typeCondition:e,directives:n,selectionSet:i}}}if(u.kind===t.Kind.INLINE_FRAGMENT&&(!u.directives||0===(null===(o=u.directives)||void 0===o?void 0:o.length))){const t=u.typeCondition?u.typeCondition.name.value:null;if(!t||t===a){s.push(...n(e,u.selectionSet.selections,i));continue}}s.push(u)}return s}Object.defineProperty(e,"__esModule",{value:!0}),e.mergeAst=function(e,r){const i=r?new t.TypeInfo(r):null,o=Object.create(null);for(const n of e.definitions)n.kind===t.Kind.FRAGMENT_DEFINITION&&(o[n.name.value]=n);const a={SelectionSet(e){const t=i?i.getParentType():null;let{selections:r}=e;return r=n(o,r,t),r=function(e,t){var n;const r=new Map,i=[];for(const o of e)if("Field"===o.kind){const e=t(o),a=r.get(e);if(null===(n=o.directives)||void 0===n?void 0:n.length){const e=Object.assign({},o);i.push(e)}else if((null==a?void 0:a.selectionSet)&&o.selectionSet)a.selectionSet.selections=[...a.selectionSet.selections,...o.selectionSet.selections];else if(!a){const t=Object.assign({},o);r.set(e,t),i.push(t)}}else i.push(o);return i}(r,(e=>e.alias?e.alias.value:e.name.value)),Object.assign(Object.assign({},e),{selections:r})},FragmentDefinition(){return null}};return(0,t.visit)(e,i?(0,t.visitWithTypeInfo)(i,a):a)}})?r.apply(t,i):r)||(e.exports=o)},1312:function(e,t){var n,r;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,void 0===(r="function"==typeof(n=function(e){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.getSelectedOperationName=function(e,t,n){if(!n||n.length<1)return;const r=n.map((e=>{var t;return null===(t=e.name)||void 0===t?void 0:t.value}));if(t&&r.includes(t))return t;if(t&&e){const n=e.map((e=>{var t;return null===(t=e.name)||void 0===t?void 0:t.value})).indexOf(t);if(-1!==n&&n{for(const e in window.localStorage)0===e.indexOf(`${t}:`)&&window.localStorage.removeItem(e)}}}get(e){if(!this.storage)return null;const n=`${t}:${e}`,r=this.storage.getItem(n);return"null"===r||"undefined"===r?(this.storage.removeItem(n),null):r||null}set(e,n){let r=!1,i=null;if(this.storage){const o=`${t}:${e}`;if(n)try{this.storage.setItem(o,n)}catch(e){i=e instanceof Error?e:new Error(`${e}`),r=function(e,t){return t instanceof DOMException&&(22===t.code||1014===t.code||"QuotaExceededError"===t.name||"NS_ERROR_DOM_QUOTA_REACHED"===t.name)&&0!==e.length}(this.storage,e)}else this.storage.removeItem(o)}return{isQuotaError:r,error:i}}clear(){this.storage&&this.storage.clear()}};const t="graphiql"})?n.apply(t,[t]):n)||(e.exports=r)},1925:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[t,n(3573),n(6837)],void 0===(o="function"==typeof(r=function(e,t,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.HistoryStore=void 0;e.HistoryStore=class{constructor(e,t){this.storage=e,this.maxHistoryLength=t,this.updateHistory=(e,t,n,r)=>{if(this.shouldSaveQuery(e,t,n,this.history.fetchRecent())){this.history.push({query:e,variables:t,headers:n,operationName:r});const i=this.history.items,o=this.favorite.items;this.queries=i.concat(o)}},this.history=new n.QueryStore("queries",this.storage,this.maxHistoryLength),this.favorite=new n.QueryStore("favorites",this.storage,null),this.queries=[...this.history.fetchAll(),...this.favorite.fetchAll()]}shouldSaveQuery(e,n,r,i){if(!e)return!1;try{(0,t.parse)(e)}catch(e){return!1}if(e.length>1e5)return!1;if(!i)return!0;if(JSON.stringify(e)===JSON.stringify(i.query)){if(JSON.stringify(n)===JSON.stringify(i.variables)){if(JSON.stringify(r)===JSON.stringify(i.headers))return!1;if(r&&!i.headers)return!1}if(n&&!i.variables)return!1}return!0}toggleFavorite(e,t,n,r,i,o){const a={query:e,variables:t,headers:n,operationName:r,label:i};this.favorite.contains(a)?o&&(a.favorite=!1,this.favorite.delete(a)):(a.favorite=!0,this.favorite.push(a)),this.queries=[...this.history.items,...this.favorite.items]}editLabel(e,t,n,r,i,o){const a={query:e,variables:t,headers:n,operationName:r,label:i};o?this.favorite.edit(Object.assign(Object.assign({},a),{favorite:o})):this.history.edit(a),this.queries=[...this.history.items,...this.favorite.items]}}})?r.apply(t,i):r)||(e.exports=o)},920:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[t,n(1180),n(1925),n(6837)],void 0===(o="function"==typeof(r=function(e,t,n,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),Object.keys(t).forEach((function(n){"default"!==n&&"__esModule"!==n&&(n in e&&e[n]===t[n]||Object.defineProperty(e,n,{enumerable:!0,get:function(){return t[n]}}))})),Object.keys(n).forEach((function(t){"default"!==t&&"__esModule"!==t&&(t in e&&e[t]===n[t]||Object.defineProperty(e,t,{enumerable:!0,get:function(){return n[t]}}))})),Object.keys(r).forEach((function(t){"default"!==t&&"__esModule"!==t&&(t in e&&e[t]===r[t]||Object.defineProperty(e,t,{enumerable:!0,get:function(){return r[t]}}))}))})?r.apply(t,i):r)||(e.exports=o)},6837:function(e,t){var n,r;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,n=function(e){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.QueryStore=void 0;e.QueryStore=class{constructor(e,t){let n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;this.key=e,this.storage=t,this.maxSize=n,this.items=this.fetchAll()}get length(){return this.items.length}contains(e){return this.items.some((t=>t.query===e.query&&t.variables===e.variables&&t.headers===e.headers&&t.operationName===e.operationName))}edit(e){const t=this.items.findIndex((t=>t.query===e.query&&t.variables===e.variables&&t.headers===e.headers&&t.operationName===e.operationName));-1!==t&&(this.items.splice(t,1,e),this.save())}delete(e){const t=this.items.findIndex((t=>t.query===e.query&&t.variables===e.variables&&t.headers===e.headers&&t.operationName===e.operationName));-1!==t&&(this.items.splice(t,1),this.save())}fetchRecent(){return this.items.at(-1)}fetchAll(){const e=this.storage.get(this.key);return e?JSON.parse(e)[this.key]:[]}push(e){const t=[...this.items,e];this.maxSize&&t.length>this.maxSize&&t.shift();for(let e=0;e<5;e++){const e=this.storage.set(this.key,JSON.stringify({[this.key]:t}));if(null==e?void 0:e.error){if(!e.isQuotaError||!this.maxSize)return;t.shift()}else this.items=t}}save(){this.storage.set(this.key,JSON.stringify({[this.key]:this.items}))}}},void 0===(r=n.apply(t,[t]))||(e.exports=r)},6676:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[t,n(7139),n(7644),n(3573),n(8506),n(5251),n(2162),n(5605),n(6785)],void 0===(o="function"==typeof(r=function(e,t,n,r,i,o,a,s,l){"use strict";function u(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(u=function(e){return e?n:t})(e)}function c(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=u(t);if(n&&n.has(e))return n.get(e);var r={},i=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var o in e)if("default"!==o&&Object.prototype.hasOwnProperty.call(e,o)){var a=i?Object.getOwnPropertyDescriptor(e,o):null;a&&(a.get||a.set)?Object.defineProperty(r,o,a):r[o]=e[o]}return r.default=e,n&&n.set(e,r),r}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0,t=c(t),r=c(r),i.GraphiQL.createFetcher=n.createGraphiQLFetcher,i.GraphiQL.GraphQL=r,i.GraphiQL.React=t;var d=i.GraphiQL;e.default=d})?r.apply(t,i):r)||(e.exports=o)},8506:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[t,n(9196),n(7139)],r=function(e,t,n){"use strict";function r(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(r=function(e){return e?n:t})(e)}function i(){return i=Object.assign?Object.assign.bind():function(e){for(var t=1;t{"first"===e&&(null==p||p.setVisiblePlugin(null))},sizeThresholdSecond:200,storageKey:"docExplorerFlex"}),T=(0,n.useDragResize)({direction:"horizontal",storageKey:"editorFlex"}),w=(0,n.useDragResize)({defaultSizeRelation:3,direction:"vertical",initiallyHidden:(()=>{if("variables"!==e.defaultEditorToolsVisibility&&"headers"!==e.defaultEditorToolsVisibility)return"boolean"==typeof e.defaultEditorToolsVisibility?e.defaultEditorToolsVisibility?void 0:"second":l.initialVariables||l.initialHeaders?void 0:"second"})(),sizeThresholdSecond:60,storageKey:"secondaryEditorFlex"}),[C,S]=(0,t.useState)((()=>"variables"===e.defaultEditorToolsVisibility||"headers"===e.defaultEditorToolsVisibility?e.defaultEditorToolsVisibility:!l.initialVariables&&l.initialHeaders&&s?"headers":"variables")),[x,k]=(0,t.useState)(null),[N,_]=(0,t.useState)(null),O=t.default.Children.toArray(e.children),I=O.find((e=>c(e,o.Logo)))||t.default.createElement(o.Logo,null),D=O.find((e=>c(e,o.Toolbar)))||t.default.createElement(t.default.Fragment,null,t.default.createElement(n.ToolbarButton,{onClick:()=>g(),label:"Prettify query (Shift-Ctrl-P)"},t.default.createElement(n.PrettifyIcon,{className:"graphiql-toolbar-icon","aria-hidden":"true"})),t.default.createElement(n.ToolbarButton,{onClick:()=>m(),label:"Merge fragments into query (Shift-Ctrl-M)"},t.default.createElement(n.MergeIcon,{className:"graphiql-toolbar-icon","aria-hidden":"true"})),t.default.createElement(n.ToolbarButton,{onClick:()=>h(),label:"Copy query (Shift-Ctrl-C)"},t.default.createElement(n.CopyIcon,{className:"graphiql-toolbar-icon","aria-hidden":"true"})),(null===(a=e.toolbar)||void 0===a?void 0:a.additionalContent)||null),L=O.find((e=>c(e,o.Footer))),A=()=>{"first"===E.hiddenElement&&E.setHiddenElement(null)},M=0===window.navigator.platform.toLowerCase().indexOf("mac")?t.default.createElement("code",{className:"graphiql-key"},"Cmd"):t.default.createElement("code",{className:"graphiql-key"},"Ctrl");return t.default.createElement("div",{"data-testid":"graphiql-container",className:"graphiql-container"},t.default.createElement("div",{className:"graphiql-sidebar"},t.default.createElement("div",{className:"graphiql-sidebar-section"},null==p?void 0:p.plugins.map((e=>{const r=e===p.visiblePlugin,i=`${r?"Hide":"Show"} ${e.title}`,o=e.icon;return t.default.createElement(n.Tooltip,{key:e.title,label:i},t.default.createElement(n.UnStyledButton,{type:"button",className:r?"active":"",onClick:()=>{r?(p.setVisiblePlugin(null),E.setHiddenElement("first")):(p.setVisiblePlugin(e),E.setHiddenElement(null))},"aria-label":i},t.default.createElement(o,{"aria-hidden":"true"})))}))),t.default.createElement("div",{className:"graphiql-sidebar-section"},t.default.createElement(n.Tooltip,{label:"Re-fetch GraphQL schema"},t.default.createElement(n.UnStyledButton,{type:"button",disabled:d.isFetching,onClick:()=>d.introspect(),"aria-label":"Re-fetch GraphQL schema"},t.default.createElement(n.ReloadIcon,{className:d.isFetching?"graphiql-spin":"","aria-hidden":"true"}))),t.default.createElement(n.Tooltip,{label:"Open short keys dialog"},t.default.createElement(n.UnStyledButton,{type:"button",onClick:()=>k("short-keys"),"aria-label":"Open short keys dialog"},t.default.createElement(n.KeyboardShortcutIcon,{"aria-hidden":"true"}))),t.default.createElement(n.Tooltip,{label:"Open settings dialog"},t.default.createElement(n.UnStyledButton,{type:"button",onClick:()=>k("settings"),"aria-label":"Open settings dialog"},t.default.createElement(n.SettingsIcon,{"aria-hidden":"true"}))))),t.default.createElement("div",{className:"graphiql-main"},t.default.createElement("div",{ref:E.firstRef,style:{minWidth:"200px"}},t.default.createElement("div",{className:"graphiql-plugin"},b?t.default.createElement(b,null):null)),t.default.createElement("div",{ref:E.dragBarRef},null!=p&&p.visiblePlugin?t.default.createElement("div",{className:"graphiql-horizontal-drag-bar"}):null),t.default.createElement("div",{ref:E.secondRef,style:{minWidth:0}},t.default.createElement("div",{className:"graphiql-sessions"},t.default.createElement("div",{className:"graphiql-session-header"},t.default.createElement(n.Tabs,{"aria-label":"Select active operation"},l.tabs.length>1?t.default.createElement(t.default.Fragment,null,l.tabs.map(((e,r)=>t.default.createElement(n.Tab,{key:e.id,isActive:r===l.activeTabIndex},t.default.createElement(n.Tab.Button,{"aria-controls":"graphiql-session",id:`graphiql-session-tab-${r}`,onClick:()=>{u.stop(),l.changeTab(r)}},e.title),t.default.createElement(n.Tab.Close,{onClick:()=>{l.activeTabIndex===r&&u.stop(),l.closeTab(r)}})))),t.default.createElement("div",null,t.default.createElement(n.Tooltip,{label:"Add tab"},t.default.createElement(n.UnStyledButton,{type:"button",className:"graphiql-tab-add",onClick:()=>l.addTab(),"aria-label":"Add tab"},t.default.createElement(n.PlusIcon,{"aria-hidden":"true"}))))):null),t.default.createElement("div",{className:"graphiql-session-header-right"},1===l.tabs.length?t.default.createElement("div",{className:"graphiql-add-tab-wrapper"},t.default.createElement(n.Tooltip,{label:"Add tab"},t.default.createElement(n.UnStyledButton,{type:"button",className:"graphiql-tab-add",onClick:()=>l.addTab(),"aria-label":"Add tab"},t.default.createElement(n.PlusIcon,{"aria-hidden":"true"})))):null,I)),t.default.createElement("div",{role:"tabpanel",id:"graphiql-session",className:"graphiql-session","aria-labelledby":`graphiql-session-tab-${l.activeTabIndex}`},t.default.createElement("div",{ref:T.firstRef},t.default.createElement("div",{className:"graphiql-editors"+(1===l.tabs.length?" full-height":"")},t.default.createElement("div",{ref:w.firstRef},t.default.createElement("section",{className:"graphiql-query-editor","aria-label":"Query Editor"},t.default.createElement("div",{className:"graphiql-query-editor-wrapper"},t.default.createElement(n.QueryEditor,{editorTheme:e.editorTheme,keyMap:e.keyMap,onClickReference:A,onCopyQuery:e.onCopyQuery,onEdit:e.onEditQuery,readOnly:e.readOnly})),t.default.createElement("div",{className:"graphiql-toolbar",role:"toolbar","aria-label":"Editor Commands"},t.default.createElement(n.ExecuteButton,null),D))),t.default.createElement("div",{ref:w.dragBarRef},t.default.createElement("div",{className:"graphiql-editor-tools"},t.default.createElement("div",{className:"graphiql-editor-tools-tabs"},t.default.createElement(n.UnStyledButton,{type:"button",className:"variables"===C&&"second"!==w.hiddenElement?"active":"",onClick:()=>{"second"===w.hiddenElement&&w.setHiddenElement(null),S("variables")}},"Variables"),s?t.default.createElement(n.UnStyledButton,{type:"button",className:"headers"===C&&"second"!==w.hiddenElement?"active":"",onClick:()=>{"second"===w.hiddenElement&&w.setHiddenElement(null),S("headers")}},"Headers"):null),t.default.createElement(n.Tooltip,{label:"second"===w.hiddenElement?"Show editor tools":"Hide editor tools"},t.default.createElement(n.UnStyledButton,{type:"button",onClick:()=>{w.setHiddenElement("second"===w.hiddenElement?null:"second")},"aria-label":"second"===w.hiddenElement?"Show editor tools":"Hide editor tools"},"second"===w.hiddenElement?t.default.createElement(n.ChevronUpIcon,{className:"graphiql-chevron-icon","aria-hidden":"true"}):t.default.createElement(n.ChevronDownIcon,{className:"graphiql-chevron-icon","aria-hidden":"true"}))))),t.default.createElement("div",{ref:w.secondRef},t.default.createElement("section",{className:"graphiql-editor-tool","aria-label":"variables"===C?"Variables":"Headers"},t.default.createElement(n.VariableEditor,{editorTheme:e.editorTheme,isHidden:"variables"!==C,keyMap:e.keyMap,onEdit:e.onEditVariables,onClickReference:A,readOnly:e.readOnly}),s&&t.default.createElement(n.HeaderEditor,{editorTheme:e.editorTheme,isHidden:"headers"!==C,keyMap:e.keyMap,onEdit:e.onEditHeaders,readOnly:e.readOnly}))))),t.default.createElement("div",{ref:T.dragBarRef},t.default.createElement("div",{className:"graphiql-horizontal-drag-bar"})),t.default.createElement("div",{ref:T.secondRef},t.default.createElement("div",{className:"graphiql-response"},u.isFetching?t.default.createElement(n.Spinner,null):null,t.default.createElement(n.ResponseEditor,{editorTheme:e.editorTheme,responseTooltip:e.responseTooltip,keyMap:e.keyMap}),L)))))),t.default.createElement(n.Dialog,{isOpen:"short-keys"===x,onDismiss:()=>k(null)},t.default.createElement("div",{className:"graphiql-dialog-header"},t.default.createElement("div",{className:"graphiql-dialog-title"},"Short Keys"),t.default.createElement(n.Dialog.Close,{onClick:()=>k(null)})),t.default.createElement("div",{className:"graphiql-dialog-section"},t.default.createElement("div",null,t.default.createElement("table",{className:"graphiql-table"},t.default.createElement("thead",null,t.default.createElement("tr",null,t.default.createElement("th",null,"Short key"),t.default.createElement("th",null,"Function"))),t.default.createElement("tbody",null,t.default.createElement("tr",null,t.default.createElement("td",null,M," + ",t.default.createElement("code",{className:"graphiql-key"},"F")),t.default.createElement("td",null,"Search in editor")),t.default.createElement("tr",null,t.default.createElement("td",null,M," + ",t.default.createElement("code",{className:"graphiql-key"},"K")),t.default.createElement("td",null,"Search in documentation")),t.default.createElement("tr",null,t.default.createElement("td",null,M," + ",t.default.createElement("code",{className:"graphiql-key"},"Enter")),t.default.createElement("td",null,"Execute query")),t.default.createElement("tr",null,t.default.createElement("td",null,t.default.createElement("code",{className:"graphiql-key"},"Ctrl")," + ",t.default.createElement("code",{className:"graphiql-key"},"Shift")," + ",t.default.createElement("code",{className:"graphiql-key"},"P")),t.default.createElement("td",null,"Prettify editors")),t.default.createElement("tr",null,t.default.createElement("td",null,t.default.createElement("code",{className:"graphiql-key"},"Ctrl")," + ",t.default.createElement("code",{className:"graphiql-key"},"Shift")," + ",t.default.createElement("code",{className:"graphiql-key"},"M")),t.default.createElement("td",null,"Merge fragments definitions into operation definition")),t.default.createElement("tr",null,t.default.createElement("td",null,t.default.createElement("code",{className:"graphiql-key"},"Ctrl")," + ",t.default.createElement("code",{className:"graphiql-key"},"Shift")," + ",t.default.createElement("code",{className:"graphiql-key"},"C")),t.default.createElement("td",null,"Copy query")),t.default.createElement("tr",null,t.default.createElement("td",null,t.default.createElement("code",{className:"graphiql-key"},"Ctrl")," + ",t.default.createElement("code",{className:"graphiql-key"},"Shift")," + ",t.default.createElement("code",{className:"graphiql-key"},"R")),t.default.createElement("td",null,"Re-fetch schema using introspection")))),t.default.createElement("p",null,"The editors use"," ",t.default.createElement("a",{href:"https://codemirror.net/5/doc/manual.html#keymaps",target:"_blank",rel:"noopener noreferrer"},"CodeMirror Key Maps")," ","that add more short keys. This instance of Graph",t.default.createElement("em",null,"i"),"QL uses"," ",t.default.createElement("code",null,e.keyMap||"sublime"),".")))),t.default.createElement(n.Dialog,{isOpen:"settings"===x,onDismiss:()=>{k(null),_(null)}},t.default.createElement("div",{className:"graphiql-dialog-header"},t.default.createElement("div",{className:"graphiql-dialog-title"},"Settings"),t.default.createElement(n.Dialog.Close,{onClick:()=>{k(null),_(null)}})),e.showPersistHeadersSettings?t.default.createElement("div",{className:"graphiql-dialog-section"},t.default.createElement("div",null,t.default.createElement("div",{className:"graphiql-dialog-section-title"},"Persist headers"),t.default.createElement("div",{className:"graphiql-dialog-section-caption"},"Save headers upon reloading."," ",t.default.createElement("span",{className:"graphiql-warning-text"},"Only enable if you trust this device."))),t.default.createElement(n.ButtonGroup,null,t.default.createElement(n.Button,{type:"button",id:"enable-persist-headers",className:l.shouldPersistHeaders?"active":void 0,onClick:()=>{l.setShouldPersistHeaders(!0)}},"On"),t.default.createElement(n.Button,{type:"button",id:"disable-persist-headers",className:l.shouldPersistHeaders?void 0:"active",onClick:()=>{l.setShouldPersistHeaders(!1)}},"Off"))):null,t.default.createElement("div",{className:"graphiql-dialog-section"},t.default.createElement("div",null,t.default.createElement("div",{className:"graphiql-dialog-section-title"},"Theme"),t.default.createElement("div",{className:"graphiql-dialog-section-caption"},"Adjust how the interface looks like.")),t.default.createElement("div",null,t.default.createElement(n.ButtonGroup,null,t.default.createElement(n.Button,{type:"button",className:null===v?"active":"",onClick:()=>y(null)},"System"),t.default.createElement(n.Button,{type:"button",className:"light"===v?"active":"",onClick:()=>y("light")},"Light"),t.default.createElement(n.Button,{type:"button",className:"dark"===v?"active":"",onClick:()=>y("dark")},"Dark")))),f?t.default.createElement("div",{className:"graphiql-dialog-section"},t.default.createElement("div",null,t.default.createElement("div",{className:"graphiql-dialog-section-title"},"Clear storage"),t.default.createElement("div",{className:"graphiql-dialog-section-caption"},"Remove all locally stored data and start fresh.")),t.default.createElement("div",null,t.default.createElement(n.Button,{type:"button",state:N||void 0,disabled:"success"===N,onClick:()=>{try{null==f||f.clear(),_("success")}catch{_("error")}}},"success"===N?"Cleared data":"error"===N?"Failed":"Clear data"))):null))}function s(e){return t.default.createElement("div",{className:"graphiql-logo"},e.children||t.default.createElement("a",{className:"graphiql-logo-link",href:"https://github.com/graphql/graphiql",target:"_blank",rel:"noreferrer"},"Graph",t.default.createElement("em",null,"i"),"QL"))}function l(e){return t.default.createElement(t.default.Fragment,null,e.children)}function u(e){return t.default.createElement("div",{className:"graphiql-footer"},e.children)}function c(e,t){var n;return!(null==e||null===(n=e.type)||void 0===n||!n.displayName||e.type.displayName!==t.displayName)||e.type===t}o.Logo=s,o.Toolbar=l,o.Footer=u,s.displayName="GraphiQLLogo",l.displayName="GraphiQLToolbar",u.displayName="GraphiQLFooter"},void 0===(o=r.apply(t,i))||(e.exports=o)},5313:function(e,t,n){"use strict";n.r(t),n.d(t,{CloseCode:function(){return r.CloseCode},GRAPHQL_TRANSPORT_WS_PROTOCOL:function(){return r.GRAPHQL_TRANSPORT_WS_PROTOCOL},MessageType:function(){return r.MessageType},createClient:function(){return o},isMessage:function(){return r.isMessage},parseMessage:function(){return r.parseMessage},stringifyMessage:function(){return r.stringifyMessage}});var r=n(863),i=n(6764);function o(e){const{url:t,connectionParams:o,lazy:s=!0,onNonLazyError:l=console.error,lazyCloseTimeout:u=0,keepAlive:c=0,disablePong:d,connectionAckWaitTimeout:f=0,retryAttempts:p=5,retryWait:h=async function(e){let t=1e3;for(let n=0;nsetTimeout(e,t+Math.floor(2700*Math.random()+300))))},isFatalConnectionProblem:m=(e=>!a(e)),on:g,webSocketImpl:v,generateID:y=function(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,(e=>{const t=16*Math.random()|0;return("x"==e?t:3&t|8).toString(16)}))},jsonMessageReplacer:b,jsonMessageReviver:E}=e;let T;if(v){if(!("function"==typeof(w=v)&&"constructor"in w&&"CLOSED"in w&&"CLOSING"in w&&"CONNECTING"in w&&"OPEN"in w))throw new Error("Invalid WebSocket implementation provided");T=v}else"undefined"!=typeof WebSocket?T=WebSocket:void 0!==n.g?T=n.g.WebSocket||n.g.MozWebSocket:"undefined"!=typeof window&&(T=window.WebSocket||window.MozWebSocket);var w;if(!T)throw new Error("WebSocket implementation missing");const C=T,S=(()=>{const e=(()=>{const e={};return{on(t,n){return e[t]=n,()=>{delete e[t]}},emit(t){var n;"id"in t&&(null===(n=e[t.id])||void 0===n||n.call(e,t))}}})(),t={connecting:(null==g?void 0:g.connecting)?[g.connecting]:[],opened:(null==g?void 0:g.opened)?[g.opened]:[],connected:(null==g?void 0:g.connected)?[g.connected]:[],ping:(null==g?void 0:g.ping)?[g.ping]:[],pong:(null==g?void 0:g.pong)?[g.pong]:[],message:(null==g?void 0:g.message)?[e.emit,g.message]:[e.emit],closed:(null==g?void 0:g.closed)?[g.closed]:[],error:(null==g?void 0:g.error)?[g.error]:[]};return{onMessage:e.on,on(e,n){const r=t[e];return r.push(n),()=>{r.splice(r.indexOf(n),1)}},emit(e,...n){for(const r of[...t[e]])r(...n)}}})();function x(e){const t=[S.on("error",(n=>{t.forEach((e=>e())),e(n)})),S.on("closed",(n=>{t.forEach((e=>e())),e(n)}))]}let k,N=0,_=!1,O=0,I=!1;async function D(){const[e,n]=await(null!=k?k:k=new Promise(((e,n)=>(async()=>{if(_){if(await h(O),!N)return k=void 0,n({code:1e3,reason:"All Subscriptions Gone"});O++}S.emit("connecting");const a=new C("function"==typeof t?await t():t,r.GRAPHQL_TRANSPORT_WS_PROTOCOL);let s,l;function u(){isFinite(c)&&c>0&&(clearTimeout(l),l=setTimeout((()=>{a.readyState===C.OPEN&&(a.send((0,r.stringifyMessage)({type:r.MessageType.Ping})),S.emit("ping",!1,void 0))}),c))}x((e=>{k=void 0,clearTimeout(s),clearTimeout(l),n(e)})),a.onerror=e=>S.emit("error",e),a.onclose=e=>S.emit("closed",e),a.onopen=async()=>{try{S.emit("opened",a);const e="function"==typeof o?await o():o;a.send((0,r.stringifyMessage)(e?{type:r.MessageType.ConnectionInit,payload:e}:{type:r.MessageType.ConnectionInit},b)),isFinite(f)&&f>0&&(s=setTimeout((()=>{a.close(r.CloseCode.ConnectionAcknowledgementTimeout,"Connection acknowledgement timeout")}),f)),u()}catch(e){S.emit("error",e),a.close(r.CloseCode.InternalClientError,(0,i.qj)(e instanceof Error?e.message:new Error(e).message,"Internal client error"))}};let p=!1;a.onmessage=({data:t})=>{try{const n=(0,r.parseMessage)(t,E);if(S.emit("message",n),"ping"===n.type||"pong"===n.type)return S.emit(n.type,!0,n.payload),void("pong"===n.type?u():d||(a.send((0,r.stringifyMessage)(n.payload?{type:r.MessageType.Pong,payload:n.payload}:{type:r.MessageType.Pong})),S.emit("pong",!1,n.payload)));if(p)return;if(n.type!==r.MessageType.ConnectionAck)throw new Error(`First message cannot be of type ${n.type}`);clearTimeout(s),p=!0,S.emit("connected",a,n.payload),_=!1,O=0,e([a,new Promise(((e,t)=>x(t)))])}catch(e){a.onmessage=null,S.emit("error",e),a.close(r.CloseCode.BadResponse,(0,i.qj)(e instanceof Error?e.message:new Error(e).message,"Bad response"))}}})())));e.readyState===C.CLOSING&&await n;let a=()=>{};const s=new Promise((e=>a=e));return[e,a,Promise.race([s.then((()=>{if(!N){const t=()=>e.close(1e3,"Normal Closure");isFinite(u)&&u>0?setTimeout((()=>{N||e.readyState!==C.OPEN||t()}),u):t()}})),n])]}function L(e){if(a(e)&&(t=e.code,![1e3,1001,1006,1005,1012,1013,1013].includes(t)&&t>=1e3&&t<=1999||[r.CloseCode.InternalServerError,r.CloseCode.InternalClientError,r.CloseCode.BadRequest,r.CloseCode.BadResponse,r.CloseCode.Unauthorized,r.CloseCode.SubprotocolNotAcceptable,r.CloseCode.SubscriberAlreadyExists,r.CloseCode.TooManyInitialisationRequests].includes(e.code)))throw e;var t;if(I)return!1;if(a(e)&&1e3===e.code)return N>0;if(!p||O>=p)throw e;if(m(e))throw e;return _=!0}return s||(async()=>{for(N++;;)try{const[,,e]=await D();await e}catch(e){try{if(!L(e))return}catch(e){return null==l?void 0:l(e)}}})(),{on:S.on,subscribe(e,t){const n=y();let i=!1,o=!1,a=()=>{N--,i=!0};return(async()=>{for(N++;;)try{const[s,l,u]=await D();if(i)return l();const c=S.onMessage(n,(e=>{switch(e.type){case r.MessageType.Next:return void t.next(e.payload);case r.MessageType.Error:return o=!0,i=!0,t.error(e.payload),void a();case r.MessageType.Complete:return i=!0,void a()}}));return s.send((0,r.stringifyMessage)({id:n,type:r.MessageType.Subscribe,payload:e},b)),a=()=>{i||s.readyState!==C.OPEN||s.send((0,r.stringifyMessage)({id:n,type:r.MessageType.Complete},b)),N--,i=!0,l()},void await u.finally(c)}catch(e){if(!L(e))return}})().then((()=>{o||t.complete()})).catch((e=>{t.error(e)})),()=>{i||a()}},async dispose(){if(I=!0,k){const[e]=await k;e.close(1e3,"Normal Closure")}}}}function a(e){return(0,i.Kn)(e)&&"code"in e&&"reason"in e}},863:function(e,t,n){"use strict";n.r(t),n.d(t,{CloseCode:function(){return o},GRAPHQL_TRANSPORT_WS_PROTOCOL:function(){return i},MessageType:function(){return a},isMessage:function(){return s},parseMessage:function(){return l},stringifyMessage:function(){return u}});var r=n(6764);const i="graphql-transport-ws";var o,a;function s(e){if((0,r.Kn)(e)){if(!(0,r.ND)(e,"type"))return!1;switch(e.type){case a.ConnectionInit:case a.ConnectionAck:case a.Ping:case a.Pong:return!(0,r.nr)(e,"payload")||void 0===e.payload||(0,r.Kn)(e.payload);case a.Subscribe:return(0,r.ND)(e,"id")&&(0,r.O2)(e,"payload")&&(!(0,r.nr)(e.payload,"operationName")||void 0===e.payload.operationName||null===e.payload.operationName||"string"==typeof e.payload.operationName)&&(0,r.ND)(e.payload,"query")&&(!(0,r.nr)(e.payload,"variables")||void 0===e.payload.variables||null===e.payload.variables||(0,r.O2)(e.payload,"variables"))&&(!(0,r.nr)(e.payload,"extensions")||void 0===e.payload.extensions||null===e.payload.extensions||(0,r.O2)(e.payload,"extensions"));case a.Next:return(0,r.ND)(e,"id")&&(0,r.O2)(e,"payload");case a.Error:return(0,r.ND)(e,"id")&&(0,r.Ox)(e.payload);case a.Complete:return(0,r.ND)(e,"id");default:return!1}}return!1}function l(e,t){if(s(e))return e;if("string"!=typeof e)throw new Error("Message not parsable");const n=JSON.parse(e,t);if(!s(n))throw new Error("Invalid message");return n}function u(e,t){if(!s(e))throw new Error("Cannot stringify invalid message");return JSON.stringify(e,t)}!function(e){e[e.InternalServerError=4500]="InternalServerError",e[e.InternalClientError=4005]="InternalClientError",e[e.BadRequest=4400]="BadRequest",e[e.BadResponse=4004]="BadResponse",e[e.Unauthorized=4401]="Unauthorized",e[e.Forbidden=4403]="Forbidden",e[e.SubprotocolNotAcceptable=4406]="SubprotocolNotAcceptable",e[e.ConnectionInitialisationTimeout=4408]="ConnectionInitialisationTimeout",e[e.ConnectionAcknowledgementTimeout=4504]="ConnectionAcknowledgementTimeout",e[e.SubscriberAlreadyExists=4409]="SubscriberAlreadyExists",e[e.TooManyInitialisationRequests=4429]="TooManyInitialisationRequests"}(o||(o={})),function(e){e.ConnectionInit="connection_init",e.ConnectionAck="connection_ack",e.Ping="ping",e.Pong="pong",e.Subscribe="subscribe",e.Next="next",e.Error="error",e.Complete="complete"}(a||(a={}))},6718:function(e,t,n){"use strict";n.r(t),n.d(t,{makeServer:function(){return f}});var r=n(953),i=n(2780),o=n(9458),a=n(4117),s=n(2941),l=n(7180),u=n(863),c=n(6764),d=function(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t,n=e[Symbol.asyncIterator];return n?n.call(e):(e="function"==typeof __values?__values(e):e[Symbol.iterator](),t={},r("next"),r("throw"),r("return"),t[Symbol.asyncIterator]=function(){return this},t);function r(n){t[n]=e[n]&&function(t){return new Promise((function(r,i){!function(e,t,n,r){Promise.resolve(r).then((function(t){e({value:t,done:n})}),t)}(r,i,(t=e[n](t)).done,t.value)}))}}};function f(e){const{schema:t,context:n,roots:f,validate:p,execute:h,subscribe:m,connectionInitWaitTimeout:g=3e3,onConnect:v,onDisconnect:y,onClose:b,onSubscribe:E,onOperation:T,onNext:w,onError:C,onComplete:S,jsonMessageReviver:x,jsonMessageReplacer:k}=e;return{opened(e,N){const _={connectionInitReceived:!1,acknowledged:!1,subscriptions:{},extra:N};if(e.protocol!==u.GRAPHQL_TRANSPORT_WS_PROTOCOL)return e.close(u.CloseCode.SubprotocolNotAcceptable,"Subprotocol not acceptable"),async(e,t)=>{await(null==b?void 0:b(_,e,t))};const O=g>0&&isFinite(g)?setTimeout((()=>{_.connectionInitReceived||e.close(u.CloseCode.ConnectionInitialisationTimeout,"Connection initialisation timeout")}),g):null;return e.onMessage((async function(g){var y,b,N;let O;try{O=(0,u.parseMessage)(g,x)}catch(t){return e.close(u.CloseCode.BadRequest,"Invalid message received")}switch(O.type){case u.MessageType.ConnectionInit:{if(_.connectionInitReceived)return e.close(u.CloseCode.TooManyInitialisationRequests,"Too many initialisation requests");_.connectionInitReceived=!0,(0,c.Kn)(O.payload)&&(_.connectionParams=O.payload);const t=await(null==v?void 0:v(_));return!1===t?e.close(u.CloseCode.Forbidden,"Forbidden"):(await e.send((0,u.stringifyMessage)((0,c.Kn)(t)?{type:u.MessageType.ConnectionAck,payload:t}:{type:u.MessageType.ConnectionAck},k)),void(_.acknowledged=!0))}case u.MessageType.Ping:return e.onPing?await e.onPing(O.payload):void await e.send((0,u.stringifyMessage)(O.payload?{type:u.MessageType.Pong,payload:O.payload}:{type:u.MessageType.Pong}));case u.MessageType.Pong:return await(null===(N=e.onPong)||void 0===N?void 0:N.call(e,O.payload));case u.MessageType.Subscribe:{if(!_.acknowledged)return e.close(u.CloseCode.Unauthorized,"Unauthorized");const{id:g,payload:v}=O;if(g in _.subscriptions)return e.close(u.CloseCode.SubscriberAlreadyExists,`Subscriber for ${g} already exists`);_.subscriptions[g]=null;const x={next:async(t,n)=>{let r={id:g,type:u.MessageType.Next,payload:t};const i=await(null==w?void 0:w(_,r,n,t));i&&(r=Object.assign(Object.assign({},r),{payload:i})),await e.send((0,u.stringifyMessage)(r,k))},error:async t=>{let n={id:g,type:u.MessageType.Error,payload:t};const r=await(null==C?void 0:C(_,n,t));r&&(n=Object.assign(Object.assign({},n),{payload:r})),await e.send((0,u.stringifyMessage)(n,k))},complete:async t=>{const n={id:g,type:u.MessageType.Complete};await(null==S?void 0:S(_,n)),t&&await e.send((0,u.stringifyMessage)(n,k))}};let N;const L=await(null==E?void 0:E(_,O));if(L){if((0,c.Ox)(L))return await x.error(L);if(Array.isArray(L))throw new Error("Invalid return value from onSubscribe hook, expected an array of GraphQLError objects");N=L}else{if(!t)throw new Error("The GraphQL schema is not provided");const e={operationName:v.operationName,document:(0,r.Qc)(v.query),variableValues:v.variables};N=Object.assign(Object.assign({},e),{schema:"function"==typeof t?await t(_,O,e):t});const n=(null!=p?p:i.Gu)(N.schema,N.document);if(n.length>0)return await x.error(n)}const A=(0,o.S)(N.document,N.operationName);if(!A)return await x.error([new a.__("Unable to identify operation")]);let M;"rootValue"in N||(N.rootValue=null==f?void 0:f[A.operation]),"contextValue"in N||(N.contextValue="function"==typeof n?await n(_,O,N):n),M="subscription"===A.operation?await(null!=m?m:s.L)(N):await(null!=h?h:l.ht)(N);const R=await(null==T?void 0:T(_,O,N,M));if(R&&(M=R),(0,c.D0)(M))if(g in _.subscriptions){_.subscriptions[g]=M;try{for(var I,D=d(M);!(I=await D.next()).done;){const e=I.value;await x.next(e,N)}}catch(e){y={error:e}}finally{try{I&&!I.done&&(b=D.return)&&await b.call(D)}finally{if(y)throw y.error}}}else(0,c.Jy)(M)&&M.return(void 0);else g in _.subscriptions&&await x.next(M,N);return await x.complete(g in _.subscriptions),void delete _.subscriptions[g]}case u.MessageType.Complete:{const e=_.subscriptions[O.id];return(0,c.Jy)(e)&&await e.return(void 0),void delete _.subscriptions[O.id]}default:throw new Error(`Unexpected message of type ${O.type} received`)}})),async(e,t)=>{O&&clearTimeout(O);for(const e of Object.values(_.subscriptions))(0,c.Jy)(e)&&await e.return(void 0);_.acknowledged&&await(null==y?void 0:y(_,e,t)),await(null==b?void 0:b(_,e,t))}}}}},6764:function(e,t,n){"use strict";n.d(t,{D0:function(){return o},Jy:function(){return a},Kn:function(){return i},ND:function(){return c},O2:function(){return u},Ox:function(){return s},nr:function(){return l},qj:function(){return d}});const r=Object.prototype.hasOwnProperty;function i(e){return"object"==typeof e&&null!==e}function o(e){return"function"==typeof Object(e)[Symbol.asyncIterator]}function a(e){return i(e)&&"function"==typeof Object(e)[Symbol.asyncIterator]&&"function"==typeof e.return}function s(e){return Array.isArray(e)&&e.length>0&&e.every((e=>"message"in e))}function l(e,t){return r.call(e,t)}function u(e,t){return r.call(e,t)&&i(e[t])}function c(e,t){return r.call(e,t)&&"string"==typeof e[t]}function d(e,t){return e.length<124?e:t}},4117:function(e,t,n){"use strict";n.d(t,{OS:function(){return l},Z:function(){return u},__:function(){return a}});var r=n(1315),i=n(3302),o=n(7026);class a extends Error{constructor(e,...t){var n,o,l;const{nodes:u,source:c,positions:d,path:f,originalError:p,extensions:h}=function(e){const t=e[0];return null==t||"kind"in t||"length"in t?{nodes:t,source:e[1],positions:e[2],path:e[3],originalError:e[4],extensions:e[5]}:t}(t);super(e),this.name="GraphQLError",this.path=null!=f?f:void 0,this.originalError=null!=p?p:void 0,this.nodes=s(Array.isArray(u)?u:u?[u]:void 0);const m=s(null===(n=this.nodes)||void 0===n?void 0:n.map((e=>e.loc)).filter((e=>null!=e)));this.source=null!=c?c:null==m||null===(o=m[0])||void 0===o?void 0:o.source,this.positions=null!=d?d:null==m?void 0:m.map((e=>e.start)),this.locations=d&&c?d.map((e=>(0,i.k)(c,e))):null==m?void 0:m.map((e=>(0,i.k)(e.source,e.start)));const g=(0,r.y)(null==p?void 0:p.extensions)?null==p?void 0:p.extensions:void 0;this.extensions=null!==(l=null!=h?h:g)&&void 0!==l?l:Object.create(null),Object.defineProperties(this,{message:{writable:!0,enumerable:!0},name:{enumerable:!1},nodes:{enumerable:!1},source:{enumerable:!1},positions:{enumerable:!1},originalError:{enumerable:!1}}),null!=p&&p.stack?Object.defineProperty(this,"stack",{value:p.stack,writable:!0,configurable:!0}):Error.captureStackTrace?Error.captureStackTrace(this,a):Object.defineProperty(this,"stack",{value:Error().stack,writable:!0,configurable:!0})}get[Symbol.toStringTag](){return"GraphQLError"}toString(){let e=this.message;if(this.nodes)for(const t of this.nodes)t.loc&&(e+="\n\n"+(0,o.Q)(t.loc));else if(this.source&&this.locations)for(const t of this.locations)e+="\n\n"+(0,o.z)(this.source,t);return e}toJSON(){const e={message:this.message};return null!=this.locations&&(e.locations=this.locations),null!=this.path&&(e.path=this.path),null!=this.extensions&&Object.keys(this.extensions).length>0&&(e.extensions=this.extensions),e}}function s(e){return void 0===e||0===e.length?void 0:e}function l(e){return e.toString()}function u(e){return e.toJSON()}},4647:function(e,t,n){"use strict";n.d(t,{y:function(){return a}});var r=n(5648);class i extends Error{constructor(e){super("Unexpected error value: "+(0,r.X)(e)),this.name="NonErrorThrown",this.thrownValue=e}}var o=n(4117);function a(e,t,n){var r;const a=(s=e)instanceof Error?s:new i(s);var s,l;return l=a,Array.isArray(l.path)?a:new o.__(a.message,{nodes:null!==(r=a.nodes)&&void 0!==r?r:t,source:a.source,positions:a.positions,path:n,originalError:a})}},2024:function(e,t,n){"use strict";n.d(t,{h:function(){return i}});var r=n(4117);function i(e,t,n){return new r.__(`Syntax Error: ${n}`,{source:e,positions:[t]})}},5267:function(e,t,n){"use strict";n.d(t,{g:function(){return l},w:function(){return u}});var r=n(3830),i=n(755),o=n(5946),a=n(5998),s=n(2806);function l(e,t,n,r,i){const o=new Map;return c(e,t,n,r,i,o,new Set),o}function u(e,t,n,r,i){const o=new Map,a=new Set;for(const s of i)s.selectionSet&&c(e,t,n,r,s.selectionSet,o,a);return o}function c(e,t,n,i,o,a,s){for(const u of o.selections)switch(u.kind){case r.h.FIELD:{if(!d(n,u))continue;const e=(l=u).alias?l.alias.value:l.name.value,t=a.get(e);void 0!==t?t.push(u):a.set(e,[u]);break}case r.h.INLINE_FRAGMENT:if(!d(n,u)||!f(e,u,i))continue;c(e,t,n,i,u.selectionSet,a,s);break;case r.h.FRAGMENT_SPREAD:{const r=u.name.value;if(s.has(r)||!d(n,u))continue;s.add(r);const o=t[r];if(!o||!f(e,o,i))continue;c(e,t,n,i,o.selectionSet,a,s);break}}var l}function d(e,t){const n=(0,s.zu)(o.QE,t,e);if(!0===(null==n?void 0:n.if))return!1;const r=(0,s.zu)(o.Yf,t,e);return!1!==(null==r?void 0:r.if)}function f(e,t,n){const r=t.typeCondition;if(!r)return!0;const o=(0,a._)(e,r);return o===n||!!(0,i.m0)(o)&&e.isSubType(o,n)}},7180:function(e,t,n){"use strict";n.d(t,{td:function(){return C},VZ:function(){return S},p$:function(){return N},El:function(){return M},mn:function(){return A},ht:function(){return E},p0:function(){return T},Vm:function(){return R}});var r=n(1172),i=n(5648),o=n(5052),a=n(2910),s=n(1315),l=n(1864),u=n(9878),c=n(4117),d=n(4647),f=n(3526),p=n(3830),h=n(755),m=n(8078),g=n(8555),v=n(5267),y=n(2806);const b=function(e){let t;return function(e,n,r){void 0===t&&(t=new WeakMap);let i=t.get(e);void 0===i&&(i=new WeakMap,t.set(e,i));let o=i.get(n);void 0===o&&(o=new WeakMap,i.set(n,o));let a=o.get(r);return void 0===a&&(s=e,l=n,u=r,a=(0,v.w)(s.schema,s.fragments,s.variableValues,l,u),o.set(r,a)),a;var s,l,u}}();function E(e){arguments.length<2||(0,r.a)(!1,"graphql@16 dropped long-deprecated support for positional arguments, please pass an object instead.");const{schema:t,document:n,variableValues:i,rootValue:o}=e;C(t,n,i);const a=S(e);if(!("schema"in a))return{errors:a};try{const{operation:e}=a,t=function(e,t,n){const r=e.schema.getRootType(t.operation);if(null==r)throw new c.__(`Schema is not configured to execute ${t.operation} operation.`,{nodes:t});const i=(0,v.g)(e.schema,e.fragments,e.variableValues,r,t.selectionSet),o=void 0;switch(t.operation){case f.ku.QUERY:return x(e,r,n,o,i);case f.ku.MUTATION:return function(e,t,n,r,i){return function(e,t,n){let r=Object.create(null);for(const n of e)r=(0,l.t)(r)?r.then((e=>t(e,n))):t(r,n);return r}(i.entries(),((r,[i,o])=>{const a=(0,u.Q)(undefined,i,t.name),s=k(e,t,n,o,a);return void 0===s?r:(0,l.t)(s)?s.then((e=>(r[i]=e,r))):(r[i]=s,r)}))}(e,r,n,0,i);case f.ku.SUBSCRIPTION:return x(e,r,n,o,i)}}(a,e,o);return(0,l.t)(t)?t.then((e=>w(e,a.errors)),(e=>(a.errors.push(e),w(null,a.errors)))):w(t,a.errors)}catch(e){return a.errors.push(e),w(null,a.errors)}}function T(e){const t=E(e);if((0,l.t)(t))throw new Error("GraphQL execution failed to complete synchronously.");return t}function w(e,t){return 0===t.length?{data:e}:{errors:t,data:e}}function C(e,t,n){t||(0,r.a)(!1,"Must provide document."),(0,g.J)(e),null==n||(0,s.y)(n)||(0,r.a)(!1,"Variables must be provided as an Object where each property is a variable value. Perhaps look to see if an unparsed JSON string was provided.")}function S(e){var t,n;const{schema:r,document:i,rootValue:o,contextValue:a,variableValues:s,operationName:l,fieldResolver:u,typeResolver:d,subscribeFieldResolver:f}=e;let h;const m=Object.create(null);for(const e of i.definitions)switch(e.kind){case p.h.OPERATION_DEFINITION:if(null==l){if(void 0!==h)return[new c.__("Must provide operation name if query contains multiple operations.")];h=e}else(null===(t=e.name)||void 0===t?void 0:t.value)===l&&(h=e);break;case p.h.FRAGMENT_DEFINITION:m[e.name.value]=e}if(!h)return null!=l?[new c.__(`Unknown operation named "${l}".`)]:[new c.__("Must provide an operation.")];const g=null!==(n=h.variableDefinitions)&&void 0!==n?n:[],v=(0,y.QF)(r,g,null!=s?s:{},{maxErrors:50});return v.errors?v.errors:{schema:r,fragments:m,rootValue:o,contextValue:a,operation:h,variableValues:v.coerced,fieldResolver:null!=u?u:M,typeResolver:null!=d?d:A,subscribeFieldResolver:null!=f?f:M,errors:[]}}function x(e,t,n,r,i){const o=Object.create(null);let a=!1;for(const[s,c]of i.entries()){const i=k(e,t,n,c,(0,u.Q)(r,s,t.name));void 0!==i&&(o[s]=i,(0,l.t)(i)&&(a=!0))}return a?(s=o,Promise.all(Object.values(s)).then((e=>{const t=Object.create(null);for(const[n,r]of Object.keys(s).entries())t[r]=e[n];return t}))):o;var s}function k(e,t,n,r,i){var o;const a=R(e.schema,t,r[0]);if(!a)return;const s=a.type,c=null!==(o=a.resolve)&&void 0!==o?o:e.fieldResolver,f=N(e,a,r,t,i);try{const t=c(n,(0,y.LX)(a,r[0],e.variableValues),e.contextValue,f);let o;return o=(0,l.t)(t)?t.then((t=>O(e,s,r,f,i,t))):O(e,s,r,f,i,t),(0,l.t)(o)?o.then(void 0,(t=>_((0,d.y)(t,r,(0,u.N)(i)),s,e))):o}catch(t){return _((0,d.y)(t,r,(0,u.N)(i)),s,e)}}function N(e,t,n,r,i){return{fieldName:t.name,fieldNodes:n,returnType:t.type,parentType:r,path:i,schema:e.schema,fragments:e.fragments,rootValue:e.rootValue,operation:e.operation,variableValues:e.variableValues}}function _(e,t,n){if((0,h.zM)(t))throw e;return n.errors.push(e),null}function O(e,t,n,r,s,f){if(f instanceof Error)throw f;if((0,h.zM)(t)){const i=O(e,t.ofType,n,r,s,f);if(null===i)throw new Error(`Cannot return null for non-nullable field ${r.parentType.name}.${r.fieldName}.`);return i}return null==f?null:(0,h.HG)(t)?function(e,t,n,r,i,o){if(!(0,a.i)(o))throw new c.__(`Expected Iterable, but did not find one for field "${r.parentType.name}.${r.fieldName}".`);const s=t.ofType;let f=!1;const p=Array.from(o,((t,o)=>{const a=(0,u.Q)(i,o,void 0);try{let i;return i=(0,l.t)(t)?t.then((t=>O(e,s,n,r,a,t))):O(e,s,n,r,a,t),(0,l.t)(i)?(f=!0,i.then(void 0,(t=>_((0,d.y)(t,n,(0,u.N)(a)),s,e)))):i}catch(t){return _((0,d.y)(t,n,(0,u.N)(a)),s,e)}}));return f?Promise.all(p):p}(e,t,n,r,s,f):(0,h.UT)(t)?function(e,t){const n=e.serialize(t);if(null==n)throw new Error(`Expected \`${(0,i.X)(e)}.serialize(${(0,i.X)(t)})\` to return non-nullable value, returned: ${(0,i.X)(n)}`);return n}(t,f):(0,h.m0)(t)?function(e,t,n,r,i,o){var a;const s=null!==(a=t.resolveType)&&void 0!==a?a:e.typeResolver,u=e.contextValue,c=s(o,u,r,t);return(0,l.t)(c)?c.then((a=>D(e,I(a,e,t,n,r,o),n,r,i,o))):D(e,I(c,e,t,n,r,o),n,r,i,o)}(e,t,n,r,s,f):(0,h.lp)(t)?D(e,t,n,r,s,f):void(0,o.k)(!1,"Cannot complete value of unexpected output type: "+(0,i.X)(t))}function I(e,t,n,r,o,a){if(null==e)throw new c.__(`Abstract type "${n.name}" must resolve to an Object type at runtime for field "${o.parentType.name}.${o.fieldName}". Either the "${n.name}" type should provide a "resolveType" function or each possible type should provide an "isTypeOf" function.`,r);if((0,h.lp)(e))throw new c.__("Support for returning GraphQLObjectType from resolveType was removed in graphql-js@16.0.0 please return type name instead.");if("string"!=typeof e)throw new c.__(`Abstract type "${n.name}" must resolve to an Object type at runtime for field "${o.parentType.name}.${o.fieldName}" with value ${(0,i.X)(a)}, received "${(0,i.X)(e)}".`);const s=t.schema.getType(e);if(null==s)throw new c.__(`Abstract type "${n.name}" was resolved to a type "${e}" that does not exist inside the schema.`,{nodes:r});if(!(0,h.lp)(s))throw new c.__(`Abstract type "${n.name}" was resolved to a non-object type "${e}".`,{nodes:r});if(!t.schema.isSubType(n,s))throw new c.__(`Runtime Object type "${s.name}" is not a possible type for "${n.name}".`,{nodes:r});return s}function D(e,t,n,r,i,o){const a=b(e,t,n);if(t.isTypeOf){const s=t.isTypeOf(o,e.contextValue,r);if((0,l.t)(s))return s.then((r=>{if(!r)throw L(t,o,n);return x(e,t,o,i,a)}));if(!s)throw L(t,o,n)}return x(e,t,o,i,a)}function L(e,t,n){return new c.__(`Expected value of type "${e.name}" but got: ${(0,i.X)(t)}.`,{nodes:n})}const A=function(e,t,n,r){if((0,s.y)(e)&&"string"==typeof e.__typename)return e.__typename;const i=n.schema.getPossibleTypes(r),o=[];for(let r=0;r{for(let t=0;t(0,c.ht)({schema:t,document:n,rootValue:e,contextValue:a,variableValues:s,operationName:l,fieldResolver:u}))):f}async function p(e,t,n,r,f,p,h){(0,c.td)(e,t,f);const m=(0,c.VZ)({schema:e,document:t,rootValue:n,contextValue:r,variableValues:f,operationName:p,subscribeFieldResolver:h});if(!("schema"in m))return{errors:m};try{const e=await async function(e){const{schema:t,fragments:n,operation:r,variableValues:i,rootValue:o}=e,f=t.getSubscriptionType();if(null==f)throw new s.__("Schema is not configured to execute subscription operation.",{nodes:r});const p=(0,u.g)(t,n,i,f,r.selectionSet),[h,m]=[...p.entries()][0],g=(0,c.Vm)(t,f,m[0]);if(!g){const e=m[0].name.value;throw new s.__(`The subscription field "${e}" is not defined.`,{nodes:m})}const v=(0,a.Q)(void 0,h,f.name),y=(0,c.p$)(e,g,m,f,v);try{var b;const t=(0,d.LX)(g,m[0],i),n=e.contextValue,r=null!==(b=g.subscribe)&&void 0!==b?b:e.subscribeFieldResolver,a=await r(o,t,n,y);if(a instanceof Error)throw a;return a}catch(e){throw(0,l.y)(e,m,(0,a.N)(v))}}(m);if(!o(e))throw new Error(`Subscription field must return Async Iterable. Received: ${(0,i.X)(e)}.`);return e}catch(e){if(e instanceof s.__)return{errors:[e]};throw e}}},2806:function(e,t,n){"use strict";n.d(t,{LX:function(){return h},QF:function(){return p},zu:function(){return m}});var r=n(5648),i=n(9815),o=n(4987),a=n(4117),s=n(3830),l=n(5895),u=n(755),c=n(5925),d=n(5998),f=n(5284);function p(e,t,n,i){const s=[],p=null==i?void 0:i.maxErrors;try{const i=function(e,t,n,i){const s={};for(const p of t){const t=p.variable.name.value,h=(0,d._)(e,p.type);if(!(0,u.j$)(h)){const e=(0,l.S)(p.type);i(new a.__(`Variable "$${t}" expected value of type "${e}" which cannot be used as an input type.`,{nodes:p.type}));continue}if(!g(n,t)){if(p.defaultValue)s[t]=(0,f.u)(p.defaultValue,h);else if((0,u.zM)(h)){const e=(0,r.X)(h);i(new a.__(`Variable "$${t}" of required type "${e}" was not provided.`,{nodes:p}))}continue}const m=n[t];if(null===m&&(0,u.zM)(h)){const e=(0,r.X)(h);i(new a.__(`Variable "$${t}" of non-null type "${e}" must not be null.`,{nodes:p}))}else s[t]=(0,c.K)(m,h,((e,n,s)=>{let l=`Variable "$${t}" got invalid value `+(0,r.X)(n);e.length>0&&(l+=` at "${t}${(0,o.F)(e)}"`),i(new a.__(l+"; "+s.message,{nodes:p,originalError:s.originalError}))}))}return s}(e,t,n,(e=>{if(null!=p&&s.length>=p)throw new a.__("Too many errors processing variables, error limit reached. Execution aborted.");s.push(e)}));if(0===s.length)return{coerced:i}}catch(e){s.push(e)}return{errors:s}}function h(e,t,n){var o;const c={},d=null!==(o=t.arguments)&&void 0!==o?o:[],p=(0,i.P)(d,(e=>e.name.value));for(const i of e.args){const e=i.name,o=i.type,d=p[e];if(!d){if(void 0!==i.defaultValue)c[e]=i.defaultValue;else if((0,u.zM)(o))throw new a.__(`Argument "${e}" of required type "${(0,r.X)(o)}" was not provided.`,{nodes:t});continue}const h=d.value;let m=h.kind===s.h.NULL;if(h.kind===s.h.VARIABLE){const t=h.name.value;if(null==n||!g(n,t)){if(void 0!==i.defaultValue)c[e]=i.defaultValue;else if((0,u.zM)(o))throw new a.__(`Argument "${e}" of required type "${(0,r.X)(o)}" was provided the variable "$${t}" which was not provided a runtime value.`,{nodes:h});continue}m=null==n[t]}if(m&&(0,u.zM)(o))throw new a.__(`Argument "${e}" of non-null type "${(0,r.X)(o)}" must not be null.`,{nodes:h});const v=(0,f.u)(h,o,n);if(void 0===v)throw new a.__(`Argument "${e}" has invalid value ${(0,l.S)(h)}.`,{nodes:h});c[e]=v}return c}function m(e,t,n){var r;const i=null===(r=t.directives)||void 0===r?void 0:r.find((t=>t.name.value===e.name));if(i)return h(e,i,n)}function g(e,t){return Object.prototype.hasOwnProperty.call(e,t)}},3573:function(e,t,n){"use strict";n.r(t),n.d(t,{BREAK:function(){return N.$_},BreakingChangeType:function(){return pt},DEFAULT_DEPRECATION_REASON:function(){return g.SY},DangerousChangeType:function(){return ht},DirectiveLocation:function(){return O.B},ExecutableDefinitionsRule:function(){return U.i},FieldsOnCorrectTypeRule:function(){return B.A},FragmentsOnCompositeTypesRule:function(){return $.T},GRAPHQL_MAX_INT:function(){return v.HI},GRAPHQL_MIN_INT:function(){return v.st},GraphQLBoolean:function(){return v.EZ},GraphQLDeprecatedDirective:function(){return g.fg},GraphQLDirective:function(){return g.NZ},GraphQLEnumType:function(){return h.mR},GraphQLError:function(){return R.__},GraphQLFloat:function(){return v.av},GraphQLID:function(){return v.km},GraphQLIncludeDirective:function(){return g.Yf},GraphQLInputObjectType:function(){return h.sR},GraphQLInt:function(){return v._o},GraphQLInterfaceType:function(){return h.oW},GraphQLList:function(){return h.p2},GraphQLNonNull:function(){return h.bM},GraphQLObjectType:function(){return h.h6},GraphQLScalarType:function(){return h.n2},GraphQLSchema:function(){return m.XO},GraphQLSkipDirective:function(){return g.QE},GraphQLSpecifiedByDirective:function(){return g.df},GraphQLString:function(){return v.kH},GraphQLUnionType:function(){return h.Gp},Kind:function(){return _.h},KnownArgumentNamesRule:function(){return q.e},KnownDirectivesRule:function(){return H.J},KnownFragmentNamesRule:function(){return G.a},KnownTypeNamesRule:function(){return z.I},Lexer:function(){return S.h},Location:function(){return E.Ye},LoneAnonymousOperationRule:function(){return W.F},LoneSchemaDefinitionRule:function(){return fe.t},NoDeprecatedCustomRule:function(){return F},NoFragmentCyclesRule:function(){return K.H},NoSchemaIntrospectionCustomRule:function(){return P},NoUndefinedVariablesRule:function(){return Q.$},NoUnusedFragmentsRule:function(){return X.J},NoUnusedVariablesRule:function(){return Y.p},OperationTypeNode:function(){return E.ku},OverlappingFieldsCanBeMergedRule:function(){return J.y},PossibleFragmentSpreadsRule:function(){return Z.a},PossibleTypeExtensionsRule:function(){return be.g},ProvidedRequiredArgumentsRule:function(){return ee.s},ScalarLeafsRule:function(){return te.O},SchemaMetaFieldDef:function(){return y.Az},SingleFieldSubscriptionsRule:function(){return ne.Z},Source:function(){return T.H},Token:function(){return E.WU},TokenKind:function(){return x.T},TypeInfo:function(){return Mt.a},TypeKind:function(){return y.zU},TypeMetaFieldDef:function(){return y.tF},TypeNameMetaFieldDef:function(){return y.hU},UniqueArgumentDefinitionNamesRule:function(){return ve.L},UniqueArgumentNamesRule:function(){return re.L},UniqueDirectiveNamesRule:function(){return ye.o},UniqueDirectivesPerLocationRule:function(){return ie.k},UniqueEnumValueNamesRule:function(){return me.L},UniqueFieldDefinitionNamesRule:function(){return ge.y},UniqueFragmentNamesRule:function(){return oe.N},UniqueInputFieldNamesRule:function(){return ae.P},UniqueOperationNamesRule:function(){return se.H},UniqueOperationTypesRule:function(){return pe.q},UniqueTypeNamesRule:function(){return he.P},UniqueVariableNamesRule:function(){return le.H},ValidationContext:function(){return j._t},ValuesOfCorrectTypeRule:function(){return ue.j},VariablesAreInputTypesRule:function(){return ce.I},VariablesInAllowedPositionRule:function(){return de.w},__Directive:function(){return y.l3},__DirectiveLocation:function(){return y.x2},__EnumValue:function(){return y.jT},__Field:function(){return y.e_},__InputValue:function(){return y.XQ},__Schema:function(){return y.TK},__Type:function(){return y.qz},__TypeKind:function(){return y.PX},assertAbstractType:function(){return h.fU},assertCompositeType:function(){return h.M_},assertDirective:function(){return g.CO},assertEnumType:function(){return h.Zu},assertEnumValueName:function(){return b.g},assertInputObjectType:function(){return h.U8},assertInputType:function(){return h.qT},assertInterfaceType:function(){return h.k2},assertLeafType:function(){return h.H5},assertListType:function(){return h.kS},assertName:function(){return b.i},assertNamedType:function(){return h.rM},assertNonNullType:function(){return h.E$},assertNullableType:function(){return h.i_},assertObjectType:function(){return h.Z6},assertOutputType:function(){return h.Gt},assertScalarType:function(){return h.Pt},assertSchema:function(){return m.EO},assertType:function(){return h.p_},assertUnionType:function(){return h.rc},assertValidName:function(){return ct},assertValidSchema:function(){return l.J},assertWrappingType:function(){return h.vX},astFromValue:function(){return Ge.J},buildASTSchema:function(){return Pe},buildClientSchema:function(){return Oe},buildSchema:function(){return je},coerceInputValue:function(){return Rt.K},concatAST:function(){return ot},createSourceEventStream:function(){return A.z},defaultFieldResolver:function(){return c.El},defaultTypeResolver:function(){return c.mn},doTypesOverlap:function(){return Ft.zR},execute:function(){return c.ht},executeSync:function(){return c.p0},extendSchema:function(){return Le},findBreakingChanges:function(){return mt},findDangerousChanges:function(){return gt},formatError:function(){return R.Z},getArgumentValues:function(){return L.LX},getDirectiveValues:function(){return L.zu},getEnterLeaveForKind:function(){return N.Eu},getIntrospectionQuery:function(){return we},getLocation:function(){return w.k},getNamedType:function(){return h.xC},getNullableType:function(){return h.tf},getOperationAST:function(){return Dt.S},getOperationRootType:function(){return Ce},getVariableValues:function(){return L.QF},getVisitFn:function(){return N.CK},graphql:function(){return d},graphqlSync:function(){return f},introspectionFromSchema:function(){return Se},introspectionTypes:function(){return y.nL},isAbstractType:function(){return h.m0},isCompositeType:function(){return h.Gv},isConstValueNode:function(){return I.Of},isDefinitionNode:function(){return I.Ir},isDirective:function(){return g.wX},isEnumType:function(){return h.EM},isEqualType:function(){return Ft._7},isExecutableDefinitionNode:function(){return I.Wk},isInputObjectType:function(){return h.hL},isInputType:function(){return h.j$},isInterfaceType:function(){return h.oT},isIntrospectionType:function(){return y.s9},isLeafType:function(){return h.UT},isListType:function(){return h.HG},isNamedType:function(){return h.Zs},isNonNullType:function(){return h.zM},isNullableType:function(){return h.zP},isObjectType:function(){return h.lp},isOutputType:function(){return h.SZ},isRequiredArgument:function(){return h.dK},isRequiredInputField:function(){return h.Wd},isScalarType:function(){return h.KA},isSchema:function(){return m.nN},isSelectionNode:function(){return I.pO},isSpecifiedDirective:function(){return g.xg},isSpecifiedScalarType:function(){return v.u1},isType:function(){return h.P9},isTypeDefinitionNode:function(){return I.zT},isTypeExtensionNode:function(){return I.D$},isTypeNode:function(){return I.VB},isTypeSubTypeOf:function(){return Ft.uJ},isTypeSystemDefinitionNode:function(){return I.G4},isTypeSystemExtensionNode:function(){return I.aU},isUnionType:function(){return h.EN},isValidNameError:function(){return dt},isValueNode:function(){return I.nr},isWrappingType:function(){return h.fw},lexicographicSortSchema:function(){return Ue},locatedError:function(){return Te.y},parse:function(){return s.Qc},parseConstValue:function(){return s.tl},parseType:function(){return s.gZ},parseValue:function(){return s.H2},print:function(){return k.S},printError:function(){return R.OS},printIntrospectionSchema:function(){return We},printLocation:function(){return C.Q},printSchema:function(){return ze},printSourceLocation:function(){return C.z},printType:function(){return Ye},resolveObjMapThunk:function(){return h.WB},resolveReadonlyArrayThunk:function(){return h._9},responsePathAsArray:function(){return D.N},separateOperations:function(){return at},specifiedDirectives:function(){return g.V4},specifiedRules:function(){return V.i},specifiedScalarTypes:function(){return v.HS},stripIgnoredCharacters:function(){return ut},subscribe:function(){return A.L},syntaxError:function(){return Ee.h},typeFromAST:function(){return Lt._},validate:function(){return u.Gu},validateSchema:function(){return l.F},valueFromAST:function(){return _e.u},valueFromASTUntyped:function(){return At.M},version:function(){return r},versionInfo:function(){return i},visit:function(){return N.Vn},visitInParallel:function(){return N.j1},visitWithTypeInfo:function(){return Mt.y}});const r="16.5.0",i=Object.freeze({major:16,minor:5,patch:0,preReleaseTag:null});var o=n(1172),a=n(1864),s=n(953),l=n(8555),u=n(2780),c=n(7180);function d(e){return new Promise((t=>t(p(e))))}function f(e){const t=p(e);if((0,a.t)(t))throw new Error("GraphQL execution failed to complete synchronously.");return t}function p(e){arguments.length<2||(0,o.a)(!1,"graphql@16 dropped long-deprecated support for positional arguments, please pass an object instead.");const{schema:t,source:n,rootValue:r,contextValue:i,variableValues:a,operationName:d,fieldResolver:f,typeResolver:p}=e,h=(0,l.F)(t);if(h.length>0)return{errors:h};let m;try{m=(0,s.Qc)(n)}catch(e){return{errors:[e]}}const g=(0,u.Gu)(t,m);return g.length>0?{errors:g}:(0,c.ht)({schema:t,document:m,rootValue:r,contextValue:i,variableValues:a,operationName:d,fieldResolver:f,typeResolver:p})}var h=n(755),m=n(773),g=n(5946),v=n(1774),y=n(8078),b=n(3228),E=n(3526),T=n(4680),w=n(3302),C=n(7026),S=n(9230),x=n(5685),k=n(5895),N=n(9685),_=n(3830),O=n(3140),I=n(9615),D=n(9878),L=n(2806),A=n(2941),M=n(5052),R=n(4117);function F(e){return{Field(t){const n=e.getFieldDef(),r=null==n?void 0:n.deprecationReason;if(n&&null!=r){const i=e.getParentType();null!=i||(0,M.k)(!1),e.reportError(new R.__(`The field ${i.name}.${n.name} is deprecated. ${r}`,{nodes:t}))}},Argument(t){const n=e.getArgument(),r=null==n?void 0:n.deprecationReason;if(n&&null!=r){const i=e.getDirective();if(null!=i)e.reportError(new R.__(`Directive "@${i.name}" argument "${n.name}" is deprecated. ${r}`,{nodes:t}));else{const i=e.getParentType(),o=e.getFieldDef();null!=i&&null!=o||(0,M.k)(!1),e.reportError(new R.__(`Field "${i.name}.${o.name}" argument "${n.name}" is deprecated. ${r}`,{nodes:t}))}}},ObjectField(t){const n=(0,h.xC)(e.getParentInputType());if((0,h.hL)(n)){const r=n.getFields()[t.name.value],i=null==r?void 0:r.deprecationReason;null!=i&&e.reportError(new R.__(`The input field ${n.name}.${r.name} is deprecated. ${i}`,{nodes:t}))}},EnumValue(t){const n=e.getEnumValue(),r=null==n?void 0:n.deprecationReason;if(n&&null!=r){const i=(0,h.xC)(e.getInputType());null!=i||(0,M.k)(!1),e.reportError(new R.__(`The enum value "${i.name}.${n.name}" is deprecated. ${r}`,{nodes:t}))}}}}function P(e){return{Field(t){const n=(0,h.xC)(e.getType());n&&(0,y.s9)(n)&&e.reportError(new R.__(`GraphQL introspection has been disabled, but the requested query contained the field "${t.name.value}".`,{nodes:t}))}}}var j=n(2716),V=n(9299),U=n(3857),B=n(1870),$=n(5167),q=n(4875),H=n(7513),G=n(1435),z=n(591),W=n(831),K=n(9316),Q=n(9518),X=n(3447),Y=n(7114),J=n(7163),Z=n(5961),ee=n(16),te=n(3989),ne=n(9309),re=n(9168),ie=n(5673),oe=n(614),ae=n(5707),se=n(2355),le=n(7417),ue=n(4697),ce=n(6192),de=n(377),fe=n(3402),pe=n(5427),he=n(4519),me=n(4560),ge=n(5240),ve=n(5947),ye=n(5681),be=n(3721),Ee=n(2024),Te=n(4647);function we(e){const t={descriptions:!0,specifiedByUrl:!1,directiveIsRepeatable:!1,schemaDescription:!1,inputValueDeprecation:!1,...e},n=t.descriptions?"description":"",r=t.specifiedByUrl?"specifiedByURL":"",i=t.directiveIsRepeatable?"isRepeatable":"";function o(e){return t.inputValueDeprecation?e:""}return`\n query IntrospectionQuery {\n __schema {\n ${t.schemaDescription?n:""}\n queryType { name }\n mutationType { name }\n subscriptionType { name }\n types {\n ...FullType\n }\n directives {\n name\n ${n}\n ${i}\n locations\n args${o("(includeDeprecated: true)")} {\n ...InputValue\n }\n }\n }\n }\n\n fragment FullType on __Type {\n kind\n name\n ${n}\n ${r}\n fields(includeDeprecated: true) {\n name\n ${n}\n args${o("(includeDeprecated: true)")} {\n ...InputValue\n }\n type {\n ...TypeRef\n }\n isDeprecated\n deprecationReason\n }\n inputFields${o("(includeDeprecated: true)")} {\n ...InputValue\n }\n interfaces {\n ...TypeRef\n }\n enumValues(includeDeprecated: true) {\n name\n ${n}\n isDeprecated\n deprecationReason\n }\n possibleTypes {\n ...TypeRef\n }\n }\n\n fragment InputValue on __InputValue {\n name\n ${n}\n type { ...TypeRef }\n defaultValue\n ${o("isDeprecated")}\n ${o("deprecationReason")}\n }\n\n fragment TypeRef on __Type {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n }\n }\n }\n }\n }\n }\n }\n }\n `}function Ce(e,t){if("query"===t.operation){const n=e.getQueryType();if(!n)throw new R.__("Schema does not define the required query root type.",{nodes:t});return n}if("mutation"===t.operation){const n=e.getMutationType();if(!n)throw new R.__("Schema is not configured for mutations.",{nodes:t});return n}if("subscription"===t.operation){const n=e.getSubscriptionType();if(!n)throw new R.__("Schema is not configured for subscriptions.",{nodes:t});return n}throw new R.__("Can only have query, mutation and subscription operations.",{nodes:t})}function Se(e,t){const n={specifiedByUrl:!0,directiveIsRepeatable:!0,schemaDescription:!0,inputValueDeprecation:!0,...t},r=(0,s.Qc)(we(n)),i=(0,c.p0)({schema:e,document:r});return!i.errors&&i.data||(0,M.k)(!1),i.data}var xe=n(5648),ke=n(1315),Ne=n(8240),_e=n(5284);function Oe(e,t){(0,ke.y)(e)&&(0,ke.y)(e.__schema)||(0,o.a)(!1,`Invalid or incomplete introspection result. Ensure that you are passing "data" property of introspection response and no "errors" was returned alongside: ${(0,xe.X)(e)}.`);const n=e.__schema,r=(0,Ne.w)(n.types,(e=>e.name),(e=>function(e){if(null!=e&&null!=e.name&&null!=e.kind)switch(e.kind){case y.zU.SCALAR:return r=e,new h.n2({name:r.name,description:r.description,specifiedByURL:r.specifiedByURL});case y.zU.OBJECT:return n=e,new h.h6({name:n.name,description:n.description,interfaces:()=>b(n),fields:()=>E(n)});case y.zU.INTERFACE:return t=e,new h.oW({name:t.name,description:t.description,interfaces:()=>b(t),fields:()=>E(t)});case y.zU.UNION:return function(e){if(!e.possibleTypes){const t=(0,xe.X)(e);throw new Error(`Introspection result missing possibleTypes: ${t}.`)}return new h.Gp({name:e.name,description:e.description,types:()=>e.possibleTypes.map(f)})}(e);case y.zU.ENUM:return function(e){if(!e.enumValues){const t=(0,xe.X)(e);throw new Error(`Introspection result missing enumValues: ${t}.`)}return new h.mR({name:e.name,description:e.description,values:(0,Ne.w)(e.enumValues,(e=>e.name),(e=>({description:e.description,deprecationReason:e.deprecationReason})))})}(e);case y.zU.INPUT_OBJECT:return function(e){if(!e.inputFields){const t=(0,xe.X)(e);throw new Error(`Introspection result missing inputFields: ${t}.`)}return new h.sR({name:e.name,description:e.description,fields:()=>w(e.inputFields)})}(e)}var t,n,r;const i=(0,xe.X)(e);throw new Error(`Invalid or incomplete introspection result. Ensure that a full introspection query is used in order to build a client schema: ${i}.`)}(e)));for(const e of[...v.HS,...y.nL])r[e.name]&&(r[e.name]=e);const i=n.queryType?f(n.queryType):null,a=n.mutationType?f(n.mutationType):null,l=n.subscriptionType?f(n.subscriptionType):null,u=n.directives?n.directives.map((function(e){if(!e.args){const t=(0,xe.X)(e);throw new Error(`Introspection result missing directive args: ${t}.`)}if(!e.locations){const t=(0,xe.X)(e);throw new Error(`Introspection result missing directive locations: ${t}.`)}return new g.NZ({name:e.name,description:e.description,isRepeatable:e.isRepeatable,locations:e.locations.slice(),args:w(e.args)})})):[];return new m.XO({description:n.description,query:i,mutation:a,subscription:l,types:Object.values(r),directives:u,assumeValid:null==t?void 0:t.assumeValid});function c(e){if(e.kind===y.zU.LIST){const t=e.ofType;if(!t)throw new Error("Decorated type deeper than introspection query.");return new h.p2(c(t))}if(e.kind===y.zU.NON_NULL){const t=e.ofType;if(!t)throw new Error("Decorated type deeper than introspection query.");const n=c(t);return new h.bM((0,h.i_)(n))}return d(e)}function d(e){const t=e.name;if(!t)throw new Error(`Unknown type reference: ${(0,xe.X)(e)}.`);const n=r[t];if(!n)throw new Error(`Invalid or incomplete schema, unknown type: ${t}. Ensure that a full introspection query is used in order to build a client schema.`);return n}function f(e){return(0,h.Z6)(d(e))}function p(e){return(0,h.k2)(d(e))}function b(e){if(null===e.interfaces&&e.kind===y.zU.INTERFACE)return[];if(!e.interfaces){const t=(0,xe.X)(e);throw new Error(`Introspection result missing interfaces: ${t}.`)}return e.interfaces.map(p)}function E(e){if(!e.fields)throw new Error(`Introspection result missing fields: ${(0,xe.X)(e)}.`);return(0,Ne.w)(e.fields,(e=>e.name),T)}function T(e){const t=c(e.type);if(!(0,h.SZ)(t)){const e=(0,xe.X)(t);throw new Error(`Introspection must provide output type for fields, but received: ${e}.`)}if(!e.args){const t=(0,xe.X)(e);throw new Error(`Introspection result missing field args: ${t}.`)}return{description:e.description,deprecationReason:e.deprecationReason,type:t,args:w(e.args)}}function w(e){return(0,Ne.w)(e,(e=>e.name),C)}function C(e){const t=c(e.type);if(!(0,h.j$)(t)){const e=(0,xe.X)(t);throw new Error(`Introspection must provide input type for arguments, but received: ${e}.`)}const n=null!=e.defaultValue?(0,_e.u)((0,s.H2)(e.defaultValue),t):void 0;return{description:e.description,type:t,defaultValue:n,deprecationReason:e.deprecationReason}}}var Ie=n(9815),De=n(9997);function Le(e,t,n){(0,m.EO)(e),null!=t&&t.kind===_.h.DOCUMENT||(0,o.a)(!1,"Must provide valid Document AST."),!0!==(null==n?void 0:n.assumeValid)&&!0!==(null==n?void 0:n.assumeValidSDL)&&(0,u.ED)(t,e);const r=e.toConfig(),i=Ae(r,t,n);return r===i?e:new m.XO(i)}function Ae(e,t,n){var r,i,o,a;const s=[],l=Object.create(null),u=[];let c;const d=[];for(const e of t.definitions)if(e.kind===_.h.SCHEMA_DEFINITION)c=e;else if(e.kind===_.h.SCHEMA_EXTENSION)d.push(e);else if((0,I.zT)(e))s.push(e);else if((0,I.D$)(e)){const t=e.name.value,n=l[t];l[t]=n?n.concat([e]):[e]}else e.kind===_.h.DIRECTIVE_DEFINITION&&u.push(e);if(0===Object.keys(l).length&&0===s.length&&0===u.length&&0===d.length&&null==c)return e;const f=Object.create(null);for(const t of e.types)f[t.name]=(p=t,(0,y.s9)(p)||(0,v.u1)(p)?p:(0,h.KA)(p)?function(e){var t;const n=e.toConfig(),r=null!==(t=l[n.name])&&void 0!==t?t:[];let i=n.specifiedByURL;for(const e of r){var o;i=null!==(o=Fe(e))&&void 0!==o?o:i}return new h.n2({...n,specifiedByURL:i,extensionASTNodes:n.extensionASTNodes.concat(r)})}(p):(0,h.lp)(p)?function(e){var t;const n=e.toConfig(),r=null!==(t=l[n.name])&&void 0!==t?t:[];return new h.h6({...n,interfaces:()=>[...e.getInterfaces().map(T),...A(r)],fields:()=>({...(0,De.j)(n.fields,w),...N(r)}),extensionASTNodes:n.extensionASTNodes.concat(r)})}(p):(0,h.oT)(p)?function(e){var t;const n=e.toConfig(),r=null!==(t=l[n.name])&&void 0!==t?t:[];return new h.oW({...n,interfaces:()=>[...e.getInterfaces().map(T),...A(r)],fields:()=>({...(0,De.j)(n.fields,w),...N(r)}),extensionASTNodes:n.extensionASTNodes.concat(r)})}(p):(0,h.EN)(p)?function(e){var t;const n=e.toConfig(),r=null!==(t=l[n.name])&&void 0!==t?t:[];return new h.Gp({...n,types:()=>[...e.getTypes().map(T),...R(r)],extensionASTNodes:n.extensionASTNodes.concat(r)})}(p):(0,h.EM)(p)?function(e){var t;const n=e.toConfig(),r=null!==(t=l[e.name])&&void 0!==t?t:[];return new h.mR({...n,values:{...n.values,...L(r)},extensionASTNodes:n.extensionASTNodes.concat(r)})}(p):(0,h.hL)(p)?function(e){var t;const n=e.toConfig(),r=null!==(t=l[n.name])&&void 0!==t?t:[];return new h.sR({...n,fields:()=>({...(0,De.j)(n.fields,(e=>({...e,type:E(e.type)}))),...D(r)}),extensionASTNodes:n.extensionASTNodes.concat(r)})}(p):void(0,M.k)(!1,"Unexpected type: "+(0,xe.X)(p)));var p;for(const e of s){var m;const t=e.name.value;f[t]=null!==(m=Me[t])&&void 0!==m?m:F(e)}const b={query:e.query&&T(e.query),mutation:e.mutation&&T(e.mutation),subscription:e.subscription&&T(e.subscription),...c&&S([c]),...S(d)};return{description:null===(r=c)||void 0===r||null===(i=r.description)||void 0===i?void 0:i.value,...b,types:Object.values(f),directives:[...e.directives.map((function(e){const t=e.toConfig();return new g.NZ({...t,args:(0,De.j)(t.args,C)})})),...u.map((function(e){var t;return new g.NZ({name:e.name.value,description:null===(t=e.description)||void 0===t?void 0:t.value,locations:e.locations.map((({value:e})=>e)),isRepeatable:e.repeatable,args:O(e.arguments),astNode:e})}))],extensions:Object.create(null),astNode:null!==(o=c)&&void 0!==o?o:e.astNode,extensionASTNodes:e.extensionASTNodes.concat(d),assumeValid:null!==(a=null==n?void 0:n.assumeValid)&&void 0!==a&&a};function E(e){return(0,h.HG)(e)?new h.p2(E(e.ofType)):(0,h.zM)(e)?new h.bM(E(e.ofType)):T(e)}function T(e){return f[e.name]}function w(e){return{...e,type:E(e.type),args:e.args&&(0,De.j)(e.args,C)}}function C(e){return{...e,type:E(e.type)}}function S(e){const t={};for(const r of e){var n;const e=null!==(n=r.operationTypes)&&void 0!==n?n:[];for(const n of e)t[n.operation]=x(n.type)}return t}function x(e){var t;const n=e.name.value,r=null!==(t=Me[n])&&void 0!==t?t:f[n];if(void 0===r)throw new Error(`Unknown type: "${n}".`);return r}function k(e){return e.kind===_.h.LIST_TYPE?new h.p2(k(e.type)):e.kind===_.h.NON_NULL_TYPE?new h.bM(k(e.type)):x(e)}function N(e){const t=Object.create(null);for(const i of e){var n;const e=null!==(n=i.fields)&&void 0!==n?n:[];for(const n of e){var r;t[n.name.value]={type:k(n.type),description:null===(r=n.description)||void 0===r?void 0:r.value,args:O(n.arguments),deprecationReason:Re(n),astNode:n}}}return t}function O(e){const t=null!=e?e:[],n=Object.create(null);for(const e of t){var r;const t=k(e.type);n[e.name.value]={type:t,description:null===(r=e.description)||void 0===r?void 0:r.value,defaultValue:(0,_e.u)(e.defaultValue,t),deprecationReason:Re(e),astNode:e}}return n}function D(e){const t=Object.create(null);for(const i of e){var n;const e=null!==(n=i.fields)&&void 0!==n?n:[];for(const n of e){var r;const e=k(n.type);t[n.name.value]={type:e,description:null===(r=n.description)||void 0===r?void 0:r.value,defaultValue:(0,_e.u)(n.defaultValue,e),deprecationReason:Re(n),astNode:n}}}return t}function L(e){const t=Object.create(null);for(const i of e){var n;const e=null!==(n=i.values)&&void 0!==n?n:[];for(const n of e){var r;t[n.name.value]={description:null===(r=n.description)||void 0===r?void 0:r.value,deprecationReason:Re(n),astNode:n}}}return t}function A(e){return e.flatMap((e=>{var t,n;return null!==(t=null===(n=e.interfaces)||void 0===n?void 0:n.map(x))&&void 0!==t?t:[]}))}function R(e){return e.flatMap((e=>{var t,n;return null!==(t=null===(n=e.types)||void 0===n?void 0:n.map(x))&&void 0!==t?t:[]}))}function F(e){var t;const n=e.name.value,r=null!==(t=l[n])&&void 0!==t?t:[];switch(e.kind){case _.h.OBJECT_TYPE_DEFINITION:{var i;const t=[e,...r];return new h.h6({name:n,description:null===(i=e.description)||void 0===i?void 0:i.value,interfaces:()=>A(t),fields:()=>N(t),astNode:e,extensionASTNodes:r})}case _.h.INTERFACE_TYPE_DEFINITION:{var o;const t=[e,...r];return new h.oW({name:n,description:null===(o=e.description)||void 0===o?void 0:o.value,interfaces:()=>A(t),fields:()=>N(t),astNode:e,extensionASTNodes:r})}case _.h.ENUM_TYPE_DEFINITION:{var a;const t=[e,...r];return new h.mR({name:n,description:null===(a=e.description)||void 0===a?void 0:a.value,values:L(t),astNode:e,extensionASTNodes:r})}case _.h.UNION_TYPE_DEFINITION:{var s;const t=[e,...r];return new h.Gp({name:n,description:null===(s=e.description)||void 0===s?void 0:s.value,types:()=>R(t),astNode:e,extensionASTNodes:r})}case _.h.SCALAR_TYPE_DEFINITION:var u;return new h.n2({name:n,description:null===(u=e.description)||void 0===u?void 0:u.value,specifiedByURL:Fe(e),astNode:e,extensionASTNodes:r});case _.h.INPUT_OBJECT_TYPE_DEFINITION:{var c;const t=[e,...r];return new h.sR({name:n,description:null===(c=e.description)||void 0===c?void 0:c.value,fields:()=>D(t),astNode:e,extensionASTNodes:r})}}}}const Me=(0,Ie.P)([...v.HS,...y.nL],(e=>e.name));function Re(e){const t=(0,L.zu)(g.fg,e);return null==t?void 0:t.reason}function Fe(e){const t=(0,L.zu)(g.df,e);return null==t?void 0:t.url}function Pe(e,t){null!=e&&e.kind===_.h.DOCUMENT||(0,o.a)(!1,"Must provide valid Document AST."),!0!==(null==t?void 0:t.assumeValid)&&!0!==(null==t?void 0:t.assumeValidSDL)&&(0,u.zo)(e);const n=Ae({description:void 0,types:[],directives:[],extensions:Object.create(null),extensionASTNodes:[],assumeValid:!1},e,t);if(null==n.astNode)for(const e of n.types)switch(e.name){case"Query":n.query=e;break;case"Mutation":n.mutation=e;break;case"Subscription":n.subscription=e}const r=[...n.directives,...g.V4.filter((e=>n.directives.every((t=>t.name!==e.name))))];return new m.XO({...n,directives:r})}function je(e,t){return Pe((0,s.Qc)(e,{noLocation:null==t?void 0:t.noLocation,allowLegacyFragmentVariables:null==t?void 0:t.allowLegacyFragmentVariables}),{assumeValidSDL:null==t?void 0:t.assumeValidSDL,assumeValid:null==t?void 0:t.assumeValid})}var Ve=n(6625);function Ue(e){const t=e.toConfig(),n=(0,Ne.w)($e(t.types),(e=>e.name),(function(e){if((0,h.KA)(e)||(0,y.s9)(e))return e;if((0,h.lp)(e)){const t=e.toConfig();return new h.h6({...t,interfaces:()=>l(t.interfaces),fields:()=>s(t.fields)})}if((0,h.oT)(e)){const t=e.toConfig();return new h.oW({...t,interfaces:()=>l(t.interfaces),fields:()=>s(t.fields)})}if((0,h.EN)(e)){const t=e.toConfig();return new h.Gp({...t,types:()=>l(t.types)})}if((0,h.EM)(e)){const t=e.toConfig();return new h.mR({...t,values:Be(t.values,(e=>e))})}if((0,h.hL)(e)){const t=e.toConfig();return new h.sR({...t,fields:()=>Be(t.fields,(e=>({...e,type:r(e.type)})))})}(0,M.k)(!1,"Unexpected type: "+(0,xe.X)(e))}));return new m.XO({...t,types:Object.values(n),directives:$e(t.directives).map((function(e){const t=e.toConfig();return new g.NZ({...t,locations:qe(t.locations,(e=>e)),args:a(t.args)})})),query:o(t.query),mutation:o(t.mutation),subscription:o(t.subscription)});function r(e){return(0,h.HG)(e)?new h.p2(r(e.ofType)):(0,h.zM)(e)?new h.bM(r(e.ofType)):i(e)}function i(e){return n[e.name]}function o(e){return e&&i(e)}function a(e){return Be(e,(e=>({...e,type:r(e.type)})))}function s(e){return Be(e,(e=>({...e,type:r(e.type),args:e.args&&a(e.args)})))}function l(e){return $e(e).map(i)}}function Be(e,t){const n=Object.create(null);for(const r of Object.keys(e).sort(Ve.K))n[r]=t(e[r]);return n}function $e(e){return qe(e,(e=>e.name))}function qe(e,t){return e.slice().sort(((e,n)=>{const r=t(e),i=t(n);return(0,Ve.K)(r,i)}))}var He=n(6303),Ge=n(3190);function ze(e){return Qe(e,(e=>!(0,g.xg)(e)),Ke)}function We(e){return Qe(e,g.xg,y.s9)}function Ke(e){return!(0,v.u1)(e)&&!(0,y.s9)(e)}function Qe(e,t,n){const r=e.getDirectives().filter(t),i=Object.values(e.getTypeMap()).filter(n);return[Xe(e),...r.map((e=>function(e){return it(e)+"directive @"+e.name+tt(e.args)+(e.isRepeatable?" repeatable":"")+" on "+e.locations.join(" | ")}(e))),...i.map((e=>Ye(e)))].filter(Boolean).join("\n\n")}function Xe(e){if(null==e.description&&function(e){const t=e.getQueryType();if(t&&"Query"!==t.name)return!1;const n=e.getMutationType();if(n&&"Mutation"!==n.name)return!1;const r=e.getSubscriptionType();return!r||"Subscription"===r.name}(e))return;const t=[],n=e.getQueryType();n&&t.push(` query: ${n.name}`);const r=e.getMutationType();r&&t.push(` mutation: ${r.name}`);const i=e.getSubscriptionType();return i&&t.push(` subscription: ${i.name}`),it(e)+`schema {\n${t.join("\n")}\n}`}function Ye(e){return(0,h.KA)(e)?function(e){return it(e)+`scalar ${e.name}`+(null==(t=e).specifiedByURL?"":` @specifiedBy(url: ${(0,k.S)({kind:_.h.STRING,value:t.specifiedByURL})})`);var t}(e):(0,h.lp)(e)?function(e){return it(e)+`type ${e.name}`+Je(e)+Ze(e)}(e):(0,h.oT)(e)?function(e){return it(e)+`interface ${e.name}`+Je(e)+Ze(e)}(e):(0,h.EN)(e)?function(e){const t=e.getTypes(),n=t.length?" = "+t.join(" | "):"";return it(e)+"union "+e.name+n}(e):(0,h.EM)(e)?function(e){const t=e.getValues().map(((e,t)=>it(e," ",!t)+" "+e.name+rt(e.deprecationReason)));return it(e)+`enum ${e.name}`+et(t)}(e):(0,h.hL)(e)?function(e){const t=Object.values(e.getFields()).map(((e,t)=>it(e," ",!t)+" "+nt(e)));return it(e)+`input ${e.name}`+et(t)}(e):void(0,M.k)(!1,"Unexpected type: "+(0,xe.X)(e))}function Je(e){const t=e.getInterfaces();return t.length?" implements "+t.map((e=>e.name)).join(" & "):""}function Ze(e){return et(Object.values(e.getFields()).map(((e,t)=>it(e," ",!t)+" "+e.name+tt(e.args," ")+": "+String(e.type)+rt(e.deprecationReason))))}function et(e){return 0!==e.length?" {\n"+e.join("\n")+"\n}":""}function tt(e,t=""){return 0===e.length?"":e.every((e=>!e.description))?"("+e.map(nt).join(", ")+")":"(\n"+e.map(((e,n)=>it(e," "+t,!n)+" "+t+nt(e))).join("\n")+"\n"+t+")"}function nt(e){const t=(0,Ge.J)(e.defaultValue,e.type);let n=e.name+": "+String(e.type);return t&&(n+=` = ${(0,k.S)(t)}`),n+rt(e.deprecationReason)}function rt(e){return null==e?"":e!==g.SY?` @deprecated(reason: ${(0,k.S)({kind:_.h.STRING,value:e})})`:" @deprecated"}function it(e,t="",n=!0){const{description:r}=e;return null==r?"":(t&&!n?"\n"+t:t)+(0,k.S)({kind:_.h.STRING,value:r,block:(0,He.MZ)(r)}).replace(/\n/g,"\n"+t)+"\n"}function ot(e){const t=[];for(const n of e)t.push(...n.definitions);return{kind:_.h.DOCUMENT,definitions:t}}function at(e){const t=[],n=Object.create(null);for(const r of e.definitions)switch(r.kind){case _.h.OPERATION_DEFINITION:t.push(r);break;case _.h.FRAGMENT_DEFINITION:n[r.name.value]=lt(r.selectionSet)}const r=Object.create(null);for(const i of t){const t=new Set;for(const e of lt(i.selectionSet))st(t,n,e);r[i.name?i.name.value:""]={kind:_.h.DOCUMENT,definitions:e.definitions.filter((e=>e===i||e.kind===_.h.FRAGMENT_DEFINITION&&t.has(e.name.value)))}}return r}function st(e,t,n){if(!e.has(n)){e.add(n);const r=t[n];if(void 0!==r)for(const n of r)st(e,t,n)}}function lt(e){const t=[];return(0,N.Vn)(e,{FragmentSpread(e){t.push(e.name.value)}}),t}function ut(e){const t=(0,T.T)(e)?e:new T.H(e),n=t.body,r=new S.h(t);let i="",o=!1;for(;r.advance().kind!==x.T.EOF;){const e=r.token,t=e.kind,a=!(0,S.u)(e.kind);o&&(a||e.kind===x.T.SPREAD)&&(i+=" ");const s=n.slice(e.start,e.end);t===x.T.BLOCK_STRING?i+=(0,He.LZ)(e.value,{minimize:!0}):i+=s,o=a}return i}function ct(e){const t=dt(e);if(t)throw t;return e}function dt(e){if("string"==typeof e||(0,o.a)(!1,"Expected name to be a string."),e.startsWith("__"))return new R.__(`Name "${e}" must not begin with "__", which is reserved by GraphQL introspection.`);try{(0,b.i)(e)}catch(e){return e}}var ft=n(4034);let pt,ht;function mt(e,t){return vt(e,t).filter((e=>e.type in pt))}function gt(e,t){return vt(e,t).filter((e=>e.type in ht))}function vt(e,t){return[...bt(e,t),...yt(e,t)]}function yt(e,t){const n=[],r=It(e.getDirectives(),t.getDirectives());for(const e of r.removed)n.push({type:pt.DIRECTIVE_REMOVED,description:`${e.name} was removed.`});for(const[e,t]of r.persisted){const r=It(e.args,t.args);for(const t of r.added)(0,h.dK)(t)&&n.push({type:pt.REQUIRED_DIRECTIVE_ARG_ADDED,description:`A required arg ${t.name} on directive ${e.name} was added.`});for(const t of r.removed)n.push({type:pt.DIRECTIVE_ARG_REMOVED,description:`${t.name} was removed from ${e.name}.`});e.isRepeatable&&!t.isRepeatable&&n.push({type:pt.DIRECTIVE_REPEATABLE_REMOVED,description:`Repeatable flag was removed from ${e.name}.`});for(const r of e.locations)t.locations.includes(r)||n.push({type:pt.DIRECTIVE_LOCATION_REMOVED,description:`${r} was removed from ${e.name}.`})}return n}function bt(e,t){const n=[],r=It(Object.values(e.getTypeMap()),Object.values(t.getTypeMap()));for(const e of r.removed)n.push({type:pt.TYPE_REMOVED,description:(0,v.u1)(e)?`Standard scalar ${e.name} was removed because it is not referenced anymore.`:`${e.name} was removed.`});for(const[e,t]of r.persisted)(0,h.EM)(e)&&(0,h.EM)(t)?n.push(...wt(e,t)):(0,h.EN)(e)&&(0,h.EN)(t)?n.push(...Tt(e,t)):(0,h.hL)(e)&&(0,h.hL)(t)?n.push(...Et(e,t)):(0,h.lp)(e)&&(0,h.lp)(t)||(0,h.oT)(e)&&(0,h.oT)(t)?n.push(...St(e,t),...Ct(e,t)):e.constructor!==t.constructor&&n.push({type:pt.TYPE_CHANGED_KIND,description:`${e.name} changed from ${_t(e)} to ${_t(t)}.`});return n}function Et(e,t){const n=[],r=It(Object.values(e.getFields()),Object.values(t.getFields()));for(const t of r.added)(0,h.Wd)(t)?n.push({type:pt.REQUIRED_INPUT_FIELD_ADDED,description:`A required field ${t.name} on input type ${e.name} was added.`}):n.push({type:ht.OPTIONAL_INPUT_FIELD_ADDED,description:`An optional field ${t.name} on input type ${e.name} was added.`});for(const t of r.removed)n.push({type:pt.FIELD_REMOVED,description:`${e.name}.${t.name} was removed.`});for(const[t,i]of r.persisted)Nt(t.type,i.type)||n.push({type:pt.FIELD_CHANGED_KIND,description:`${e.name}.${t.name} changed type from ${String(t.type)} to ${String(i.type)}.`});return n}function Tt(e,t){const n=[],r=It(e.getTypes(),t.getTypes());for(const t of r.added)n.push({type:ht.TYPE_ADDED_TO_UNION,description:`${t.name} was added to union type ${e.name}.`});for(const t of r.removed)n.push({type:pt.TYPE_REMOVED_FROM_UNION,description:`${t.name} was removed from union type ${e.name}.`});return n}function wt(e,t){const n=[],r=It(e.getValues(),t.getValues());for(const t of r.added)n.push({type:ht.VALUE_ADDED_TO_ENUM,description:`${t.name} was added to enum type ${e.name}.`});for(const t of r.removed)n.push({type:pt.VALUE_REMOVED_FROM_ENUM,description:`${t.name} was removed from enum type ${e.name}.`});return n}function Ct(e,t){const n=[],r=It(e.getInterfaces(),t.getInterfaces());for(const t of r.added)n.push({type:ht.IMPLEMENTED_INTERFACE_ADDED,description:`${t.name} added to interfaces implemented by ${e.name}.`});for(const t of r.removed)n.push({type:pt.IMPLEMENTED_INTERFACE_REMOVED,description:`${e.name} no longer implements interface ${t.name}.`});return n}function St(e,t){const n=[],r=It(Object.values(e.getFields()),Object.values(t.getFields()));for(const t of r.removed)n.push({type:pt.FIELD_REMOVED,description:`${e.name}.${t.name} was removed.`});for(const[t,i]of r.persisted)n.push(...xt(e,t,i)),kt(t.type,i.type)||n.push({type:pt.FIELD_CHANGED_KIND,description:`${e.name}.${t.name} changed type from ${String(t.type)} to ${String(i.type)}.`});return n}function xt(e,t,n){const r=[],i=It(t.args,n.args);for(const n of i.removed)r.push({type:pt.ARG_REMOVED,description:`${e.name}.${t.name} arg ${n.name} was removed.`});for(const[n,o]of i.persisted)if(Nt(n.type,o.type)){if(void 0!==n.defaultValue)if(void 0===o.defaultValue)r.push({type:ht.ARG_DEFAULT_VALUE_CHANGE,description:`${e.name}.${t.name} arg ${n.name} defaultValue was removed.`});else{const i=Ot(n.defaultValue,n.type),a=Ot(o.defaultValue,o.type);i!==a&&r.push({type:ht.ARG_DEFAULT_VALUE_CHANGE,description:`${e.name}.${t.name} arg ${n.name} has changed defaultValue from ${i} to ${a}.`})}}else r.push({type:pt.ARG_CHANGED_KIND,description:`${e.name}.${t.name} arg ${n.name} has changed type from ${String(n.type)} to ${String(o.type)}.`});for(const n of i.added)(0,h.dK)(n)?r.push({type:pt.REQUIRED_ARG_ADDED,description:`A required arg ${n.name} on ${e.name}.${t.name} was added.`}):r.push({type:ht.OPTIONAL_ARG_ADDED,description:`An optional arg ${n.name} on ${e.name}.${t.name} was added.`});return r}function kt(e,t){return(0,h.HG)(e)?(0,h.HG)(t)&&kt(e.ofType,t.ofType)||(0,h.zM)(t)&&kt(e,t.ofType):(0,h.zM)(e)?(0,h.zM)(t)&&kt(e.ofType,t.ofType):(0,h.Zs)(t)&&e.name===t.name||(0,h.zM)(t)&&kt(e,t.ofType)}function Nt(e,t){return(0,h.HG)(e)?(0,h.HG)(t)&&Nt(e.ofType,t.ofType):(0,h.zM)(e)?(0,h.zM)(t)&&Nt(e.ofType,t.ofType)||!(0,h.zM)(t)&&Nt(e.ofType,t):(0,h.Zs)(t)&&e.name===t.name}function _t(e){return(0,h.KA)(e)?"a Scalar type":(0,h.lp)(e)?"an Object type":(0,h.oT)(e)?"an Interface type":(0,h.EN)(e)?"a Union type":(0,h.EM)(e)?"an Enum type":(0,h.hL)(e)?"an Input type":void(0,M.k)(!1,"Unexpected type: "+(0,xe.X)(e))}function Ot(e,t){const n=(0,Ge.J)(e,t);return null!=n||(0,M.k)(!1),(0,k.S)((0,ft.n)(n))}function It(e,t){const n=[],r=[],i=[],o=(0,Ie.P)(e,(({name:e})=>e)),a=(0,Ie.P)(t,(({name:e})=>e));for(const t of e){const e=a[t.name];void 0===e?r.push(t):i.push([t,e])}for(const e of t)void 0===o[e.name]&&n.push(e);return{added:n,persisted:i,removed:r}}!function(e){e.TYPE_REMOVED="TYPE_REMOVED",e.TYPE_CHANGED_KIND="TYPE_CHANGED_KIND",e.TYPE_REMOVED_FROM_UNION="TYPE_REMOVED_FROM_UNION",e.VALUE_REMOVED_FROM_ENUM="VALUE_REMOVED_FROM_ENUM",e.REQUIRED_INPUT_FIELD_ADDED="REQUIRED_INPUT_FIELD_ADDED",e.IMPLEMENTED_INTERFACE_REMOVED="IMPLEMENTED_INTERFACE_REMOVED",e.FIELD_REMOVED="FIELD_REMOVED",e.FIELD_CHANGED_KIND="FIELD_CHANGED_KIND",e.REQUIRED_ARG_ADDED="REQUIRED_ARG_ADDED",e.ARG_REMOVED="ARG_REMOVED",e.ARG_CHANGED_KIND="ARG_CHANGED_KIND",e.DIRECTIVE_REMOVED="DIRECTIVE_REMOVED",e.DIRECTIVE_ARG_REMOVED="DIRECTIVE_ARG_REMOVED",e.REQUIRED_DIRECTIVE_ARG_ADDED="REQUIRED_DIRECTIVE_ARG_ADDED",e.DIRECTIVE_REPEATABLE_REMOVED="DIRECTIVE_REPEATABLE_REMOVED",e.DIRECTIVE_LOCATION_REMOVED="DIRECTIVE_LOCATION_REMOVED"}(pt||(pt={})),function(e){e.VALUE_ADDED_TO_ENUM="VALUE_ADDED_TO_ENUM",e.TYPE_ADDED_TO_UNION="TYPE_ADDED_TO_UNION",e.OPTIONAL_INPUT_FIELD_ADDED="OPTIONAL_INPUT_FIELD_ADDED",e.OPTIONAL_ARG_ADDED="OPTIONAL_ARG_ADDED",e.IMPLEMENTED_INTERFACE_ADDED="IMPLEMENTED_INTERFACE_ADDED",e.ARG_DEFAULT_VALUE_CHANGE="ARG_DEFAULT_VALUE_CHANGE"}(ht||(ht={}));var Dt=n(9458),Lt=n(5998),At=n(9426),Mt=n(1409),Rt=n(5925),Ft=n(2984)},9878:function(e,t,n){"use strict";function r(e,t,n){return{prev:e,key:t,typename:n}}function i(e){const t=[];let n=e;for(;n;)t.push(n.key),n=n.prev;return t.reverse()}n.d(t,{N:function(){return i},Q:function(){return r}})},1172:function(e,t,n){"use strict";function r(e,t){if(!Boolean(e))throw new Error(t)}n.d(t,{a:function(){return r}})},8063:function(e,t,n){"use strict";n.d(t,{l:function(){return i}});const r=5;function i(e,t){const[n,i]=t?[e,t]:[void 0,e];let o=" Did you mean ";n&&(o+=n+" ");const a=i.map((e=>`"${e}"`));switch(a.length){case 0:return"";case 1:return o+a[0]+"?";case 2:return o+a[0]+" or "+a[1]+"?"}const s=a.slice(0,r),l=s.pop();return o+s.join(", ")+", or "+l+"?"}},5839:function(e,t,n){"use strict";function r(e,t){const n=new Map;for(const r of e){const e=t(r),i=n.get(e);void 0===i?n.set(e,[r]):i.push(r)}return n}n.d(t,{v:function(){return r}})},5648:function(e,t,n){"use strict";n.d(t,{X:function(){return o}});const r=10,i=2;function o(e){return a(e,[])}function a(e,t){switch(typeof e){case"string":return JSON.stringify(e);case"function":return e.name?`[function ${e.name}]`:"[function]";case"object":return function(e,t){if(null===e)return"null";if(t.includes(e))return"[Circular]";const n=[...t,e];if(function(e){return"function"==typeof e.toJSON}(e)){const t=e.toJSON();if(t!==e)return"string"==typeof t?t:a(t,n)}else if(Array.isArray(e))return function(e,t){if(0===e.length)return"[]";if(t.length>i)return"[Array]";const n=Math.min(r,e.length),o=e.length-n,s=[];for(let r=0;r1&&s.push(`... ${o} more items`),"["+s.join(", ")+"]"}(e,n);return function(e,t){const n=Object.entries(e);if(0===n.length)return"{}";if(t.length>i)return"["+function(e){const t=Object.prototype.toString.call(e).replace(/^\[object /,"").replace(/]$/,"");if("Object"===t&&"function"==typeof e.constructor){const t=e.constructor.name;if("string"==typeof t&&""!==t)return t}return t}(e)+"]";const r=n.map((([e,n])=>e+": "+a(n,t)));return"{ "+r.join(", ")+" }"}(e,n)}(e,t);default:return String(e)}}},1513:function(e,t,n){"use strict";n.d(t,{n:function(){return r}});const r=function(e,t){return e instanceof t}},5052:function(e,t,n){"use strict";function r(e,t){if(!Boolean(e))throw new Error(null!=t?t:"Unexpected invariant triggered.")}n.d(t,{k:function(){return r}})},2910:function(e,t,n){"use strict";function r(e){return"object"==typeof e&&"function"==typeof(null==e?void 0:e[Symbol.iterator])}n.d(t,{i:function(){return r}})},1315:function(e,t,n){"use strict";function r(e){return"object"==typeof e&&null!==e}n.d(t,{y:function(){return r}})},1864:function(e,t,n){"use strict";function r(e){return"function"==typeof(null==e?void 0:e.then)}n.d(t,{t:function(){return r}})},9815:function(e,t,n){"use strict";function r(e,t){const n=Object.create(null);for(const r of e)n[t(r)]=r;return n}n.d(t,{P:function(){return r}})},8240:function(e,t,n){"use strict";function r(e,t,n){const r=Object.create(null);for(const i of e)r[t(i)]=n(i);return r}n.d(t,{w:function(){return r}})},9997:function(e,t,n){"use strict";function r(e,t){const n=Object.create(null);for(const r of Object.keys(e))n[r]=t(e[r],r);return n}n.d(t,{j:function(){return r}})},6625:function(e,t,n){"use strict";function r(e,t){let n=0,r=0;for(;n0);let u=0;do{++r,u=10*u+s-i,s=t.charCodeAt(r)}while(a(s)&&u>0);if(lu)return 1}else{if(os)return 1;++n,++r}}return e.length-t.length}n.d(t,{K:function(){return r}});const i=48,o=57;function a(e){return!isNaN(e)&&i<=e&&e<=o}},4987:function(e,t,n){"use strict";function r(e){return e.map((e=>"number"==typeof e?"["+e.toString()+"]":"."+e)).join("")}n.d(t,{F:function(){return r}})},3492:function(e,t,n){"use strict";n.d(t,{D:function(){return i}});var r=n(6625);function i(e,t){const n=Object.create(null),i=new o(e),a=Math.floor(.4*e.length)+1;for(const e of t){const t=i.measure(e,a);void 0!==t&&(n[e]=t)}return Object.keys(n).sort(((e,t)=>{const i=n[e]-n[t];return 0!==i?i:(0,r.K)(e,t)}))}class o{constructor(e){this._input=e,this._inputLowerCase=e.toLowerCase(),this._inputArray=a(this._inputLowerCase),this._rows=[new Array(e.length+1).fill(0),new Array(e.length+1).fill(0),new Array(e.length+1).fill(0)]}measure(e,t){if(this._input===e)return 0;const n=e.toLowerCase();if(this._inputLowerCase===n)return 1;let r=a(n),i=this._inputArray;if(r.lengtht)return;const l=this._rows;for(let e=0;e<=s;e++)l[0][e]=e;for(let e=1;e<=o;e++){const n=l[(e-1)%3],o=l[e%3];let a=o[0]=e;for(let t=1;t<=s;t++){const s=r[e-1]===i[t-1]?0:1;let u=Math.min(n[t]+1,o[t-1]+1,n[t-1]+s);if(e>1&&t>1&&r[e-1]===i[t-2]&&r[e-2]===i[t-1]){const n=l[(e-2)%3][t-2];u=Math.min(u,n+1)}ut)return}const u=l[o%3][s];return u<=t?u:void 0}}function a(e){const t=e.length,n=new Array(t);for(let r=0;r0===t?e:e.slice(n))).slice(null!==(t=r)&&void 0!==t?t:0,i+1)}function o(e){let t=0;for(;t1&&i.slice(1).every((e=>0===e.length||(0,r.FD)(e.charCodeAt(0)))),s=n.endsWith('\\"""'),l=e.endsWith('"')&&!s,u=e.endsWith("\\"),c=l||u,d=!(null!=t&&t.minimize)&&(!o||e.length>70||c||a||s);let f="";const p=o&&(0,r.FD)(e.charCodeAt(0));return(d&&!p||a)&&(f+="\n"),f+=n,(d||c)&&(f+="\n"),'"""'+f+'"""'}},1117:function(e,t,n){"use strict";function r(e){return 9===e||32===e}function i(e){return e>=48&&e<=57}function o(e){return e>=97&&e<=122||e>=65&&e<=90}function a(e){return o(e)||95===e}function s(e){return o(e)||i(e)||95===e}n.d(t,{FD:function(){return r},HQ:function(){return s},LQ:function(){return a},X1:function(){return i}})},3140:function(e,t,n){"use strict";let r;n.d(t,{B:function(){return r}}),function(e){e.QUERY="QUERY",e.MUTATION="MUTATION",e.SUBSCRIPTION="SUBSCRIPTION",e.FIELD="FIELD",e.FRAGMENT_DEFINITION="FRAGMENT_DEFINITION",e.FRAGMENT_SPREAD="FRAGMENT_SPREAD",e.INLINE_FRAGMENT="INLINE_FRAGMENT",e.VARIABLE_DEFINITION="VARIABLE_DEFINITION",e.SCHEMA="SCHEMA",e.SCALAR="SCALAR",e.OBJECT="OBJECT",e.FIELD_DEFINITION="FIELD_DEFINITION",e.ARGUMENT_DEFINITION="ARGUMENT_DEFINITION",e.INTERFACE="INTERFACE",e.UNION="UNION",e.ENUM="ENUM",e.ENUM_VALUE="ENUM_VALUE",e.INPUT_OBJECT="INPUT_OBJECT",e.INPUT_FIELD_DEFINITION="INPUT_FIELD_DEFINITION"}(r||(r={}))},3830:function(e,t,n){"use strict";let r;n.d(t,{h:function(){return r}}),function(e){e.NAME="Name",e.DOCUMENT="Document",e.OPERATION_DEFINITION="OperationDefinition",e.VARIABLE_DEFINITION="VariableDefinition",e.SELECTION_SET="SelectionSet",e.FIELD="Field",e.ARGUMENT="Argument",e.FRAGMENT_SPREAD="FragmentSpread",e.INLINE_FRAGMENT="InlineFragment",e.FRAGMENT_DEFINITION="FragmentDefinition",e.VARIABLE="Variable",e.INT="IntValue",e.FLOAT="FloatValue",e.STRING="StringValue",e.BOOLEAN="BooleanValue",e.NULL="NullValue",e.ENUM="EnumValue",e.LIST="ListValue",e.OBJECT="ObjectValue",e.OBJECT_FIELD="ObjectField",e.DIRECTIVE="Directive",e.NAMED_TYPE="NamedType",e.LIST_TYPE="ListType",e.NON_NULL_TYPE="NonNullType",e.SCHEMA_DEFINITION="SchemaDefinition",e.OPERATION_TYPE_DEFINITION="OperationTypeDefinition",e.SCALAR_TYPE_DEFINITION="ScalarTypeDefinition",e.OBJECT_TYPE_DEFINITION="ObjectTypeDefinition",e.FIELD_DEFINITION="FieldDefinition",e.INPUT_VALUE_DEFINITION="InputValueDefinition",e.INTERFACE_TYPE_DEFINITION="InterfaceTypeDefinition",e.UNION_TYPE_DEFINITION="UnionTypeDefinition",e.ENUM_TYPE_DEFINITION="EnumTypeDefinition",e.ENUM_VALUE_DEFINITION="EnumValueDefinition",e.INPUT_OBJECT_TYPE_DEFINITION="InputObjectTypeDefinition",e.DIRECTIVE_DEFINITION="DirectiveDefinition",e.SCHEMA_EXTENSION="SchemaExtension",e.SCALAR_TYPE_EXTENSION="ScalarTypeExtension",e.OBJECT_TYPE_EXTENSION="ObjectTypeExtension",e.INTERFACE_TYPE_EXTENSION="InterfaceTypeExtension",e.UNION_TYPE_EXTENSION="UnionTypeExtension",e.ENUM_TYPE_EXTENSION="EnumTypeExtension",e.INPUT_OBJECT_TYPE_EXTENSION="InputObjectTypeExtension"}(r||(r={}))},9230:function(e,t,n){"use strict";n.d(t,{h:function(){return l},u:function(){return u}});var r=n(2024),i=n(3526),o=n(6303),a=n(1117),s=n(5685);class l{constructor(e){const t=new i.WU(s.T.SOF,0,0,0,0);this.source=e,this.lastToken=t,this.token=t,this.line=1,this.lineStart=0}get[Symbol.toStringTag](){return"Lexer"}advance(){return this.lastToken=this.token,this.token=this.lookahead()}lookahead(){let e=this.token;if(e.kind!==s.T.EOF)do{if(e.next)e=e.next;else{const t=g(this,e.end);e.next=t,t.prev=e,e=t}}while(e.kind===s.T.COMMENT);return e}}function u(e){return e===s.T.BANG||e===s.T.DOLLAR||e===s.T.AMP||e===s.T.PAREN_L||e===s.T.PAREN_R||e===s.T.SPREAD||e===s.T.COLON||e===s.T.EQUALS||e===s.T.AT||e===s.T.BRACKET_L||e===s.T.BRACKET_R||e===s.T.BRACE_L||e===s.T.PIPE||e===s.T.BRACE_R}function c(e){return e>=0&&e<=55295||e>=57344&&e<=1114111}function d(e,t){return f(e.charCodeAt(t))&&p(e.charCodeAt(t+1))}function f(e){return e>=55296&&e<=56319}function p(e){return e>=56320&&e<=57343}function h(e,t){const n=e.source.body.codePointAt(t);if(void 0===n)return s.T.EOF;if(n>=32&&n<=126){const e=String.fromCodePoint(n);return'"'===e?"'\"'":`"${e}"`}return"U+"+n.toString(16).toUpperCase().padStart(4,"0")}function m(e,t,n,r,o){const a=e.line,s=1+n-e.lineStart;return new i.WU(t,n,r,a,s,o)}function g(e,t){const n=e.source.body,i=n.length;let o=t;for(;o=48&&e<=57?e-48:e>=65&&e<=70?e-55:e>=97&&e<=102?e-87:-1}function x(e,t){const n=e.source.body;switch(n.charCodeAt(t+1)){case 34:return{value:'"',size:2};case 92:return{value:"\\",size:2};case 47:return{value:"/",size:2};case 98:return{value:"\b",size:2};case 102:return{value:"\f",size:2};case 110:return{value:"\n",size:2};case 114:return{value:"\r",size:2};case 116:return{value:"\t",size:2}}throw(0,r.h)(e.source,t,`Invalid character escape sequence: "${n.slice(t,t+2)}".`)}function k(e,t){const n=e.source.body,i=n.length;let a=e.lineStart,l=t+3,u=l,f="";const p=[];for(;l=t)break;n=a.index+a[0].length,o+=1}return{line:o,column:t+1-n}}},953:function(e,t,n){"use strict";n.d(t,{H2:function(){return d},Qc:function(){return c},gZ:function(){return p},tl:function(){return f}});var r=n(2024),i=n(3526),o=n(3140),a=n(3830),s=n(9230),l=n(4680),u=n(5685);function c(e,t){return new h(e,t).parseDocument()}function d(e,t){const n=new h(e,t);n.expectToken(u.T.SOF);const r=n.parseValueLiteral(!1);return n.expectToken(u.T.EOF),r}function f(e,t){const n=new h(e,t);n.expectToken(u.T.SOF);const r=n.parseConstValueLiteral();return n.expectToken(u.T.EOF),r}function p(e,t){const n=new h(e,t);n.expectToken(u.T.SOF);const r=n.parseTypeReference();return n.expectToken(u.T.EOF),r}class h{constructor(e,t){const n=(0,l.T)(e)?e:new l.H(e);this._lexer=new s.h(n),this._options=t}parseName(){const e=this.expectToken(u.T.NAME);return this.node(e,{kind:a.h.NAME,value:e.value})}parseDocument(){return this.node(this._lexer.token,{kind:a.h.DOCUMENT,definitions:this.many(u.T.SOF,this.parseDefinition,u.T.EOF)})}parseDefinition(){if(this.peek(u.T.BRACE_L))return this.parseOperationDefinition();const e=this.peekDescription(),t=e?this._lexer.lookahead():this._lexer.token;if(t.kind===u.T.NAME){switch(t.value){case"schema":return this.parseSchemaDefinition();case"scalar":return this.parseScalarTypeDefinition();case"type":return this.parseObjectTypeDefinition();case"interface":return this.parseInterfaceTypeDefinition();case"union":return this.parseUnionTypeDefinition();case"enum":return this.parseEnumTypeDefinition();case"input":return this.parseInputObjectTypeDefinition();case"directive":return this.parseDirectiveDefinition()}if(e)throw(0,r.h)(this._lexer.source,this._lexer.token.start,"Unexpected description, descriptions are supported only on type definitions.");switch(t.value){case"query":case"mutation":case"subscription":return this.parseOperationDefinition();case"fragment":return this.parseFragmentDefinition();case"extend":return this.parseTypeSystemExtension()}}throw this.unexpected(t)}parseOperationDefinition(){const e=this._lexer.token;if(this.peek(u.T.BRACE_L))return this.node(e,{kind:a.h.OPERATION_DEFINITION,operation:i.ku.QUERY,name:void 0,variableDefinitions:[],directives:[],selectionSet:this.parseSelectionSet()});const t=this.parseOperationType();let n;return this.peek(u.T.NAME)&&(n=this.parseName()),this.node(e,{kind:a.h.OPERATION_DEFINITION,operation:t,name:n,variableDefinitions:this.parseVariableDefinitions(),directives:this.parseDirectives(!1),selectionSet:this.parseSelectionSet()})}parseOperationType(){const e=this.expectToken(u.T.NAME);switch(e.value){case"query":return i.ku.QUERY;case"mutation":return i.ku.MUTATION;case"subscription":return i.ku.SUBSCRIPTION}throw this.unexpected(e)}parseVariableDefinitions(){return this.optionalMany(u.T.PAREN_L,this.parseVariableDefinition,u.T.PAREN_R)}parseVariableDefinition(){return this.node(this._lexer.token,{kind:a.h.VARIABLE_DEFINITION,variable:this.parseVariable(),type:(this.expectToken(u.T.COLON),this.parseTypeReference()),defaultValue:this.expectOptionalToken(u.T.EQUALS)?this.parseConstValueLiteral():void 0,directives:this.parseConstDirectives()})}parseVariable(){const e=this._lexer.token;return this.expectToken(u.T.DOLLAR),this.node(e,{kind:a.h.VARIABLE,name:this.parseName()})}parseSelectionSet(){return this.node(this._lexer.token,{kind:a.h.SELECTION_SET,selections:this.many(u.T.BRACE_L,this.parseSelection,u.T.BRACE_R)})}parseSelection(){return this.peek(u.T.SPREAD)?this.parseFragment():this.parseField()}parseField(){const e=this._lexer.token,t=this.parseName();let n,r;return this.expectOptionalToken(u.T.COLON)?(n=t,r=this.parseName()):r=t,this.node(e,{kind:a.h.FIELD,alias:n,name:r,arguments:this.parseArguments(!1),directives:this.parseDirectives(!1),selectionSet:this.peek(u.T.BRACE_L)?this.parseSelectionSet():void 0})}parseArguments(e){const t=e?this.parseConstArgument:this.parseArgument;return this.optionalMany(u.T.PAREN_L,t,u.T.PAREN_R)}parseArgument(e=!1){const t=this._lexer.token,n=this.parseName();return this.expectToken(u.T.COLON),this.node(t,{kind:a.h.ARGUMENT,name:n,value:this.parseValueLiteral(e)})}parseConstArgument(){return this.parseArgument(!0)}parseFragment(){const e=this._lexer.token;this.expectToken(u.T.SPREAD);const t=this.expectOptionalKeyword("on");return!t&&this.peek(u.T.NAME)?this.node(e,{kind:a.h.FRAGMENT_SPREAD,name:this.parseFragmentName(),directives:this.parseDirectives(!1)}):this.node(e,{kind:a.h.INLINE_FRAGMENT,typeCondition:t?this.parseNamedType():void 0,directives:this.parseDirectives(!1),selectionSet:this.parseSelectionSet()})}parseFragmentDefinition(){var e;const t=this._lexer.token;return this.expectKeyword("fragment"),!0===(null===(e=this._options)||void 0===e?void 0:e.allowLegacyFragmentVariables)?this.node(t,{kind:a.h.FRAGMENT_DEFINITION,name:this.parseFragmentName(),variableDefinitions:this.parseVariableDefinitions(),typeCondition:(this.expectKeyword("on"),this.parseNamedType()),directives:this.parseDirectives(!1),selectionSet:this.parseSelectionSet()}):this.node(t,{kind:a.h.FRAGMENT_DEFINITION,name:this.parseFragmentName(),typeCondition:(this.expectKeyword("on"),this.parseNamedType()),directives:this.parseDirectives(!1),selectionSet:this.parseSelectionSet()})}parseFragmentName(){if("on"===this._lexer.token.value)throw this.unexpected();return this.parseName()}parseValueLiteral(e){const t=this._lexer.token;switch(t.kind){case u.T.BRACKET_L:return this.parseList(e);case u.T.BRACE_L:return this.parseObject(e);case u.T.INT:return this._lexer.advance(),this.node(t,{kind:a.h.INT,value:t.value});case u.T.FLOAT:return this._lexer.advance(),this.node(t,{kind:a.h.FLOAT,value:t.value});case u.T.STRING:case u.T.BLOCK_STRING:return this.parseStringLiteral();case u.T.NAME:switch(this._lexer.advance(),t.value){case"true":return this.node(t,{kind:a.h.BOOLEAN,value:!0});case"false":return this.node(t,{kind:a.h.BOOLEAN,value:!1});case"null":return this.node(t,{kind:a.h.NULL});default:return this.node(t,{kind:a.h.ENUM,value:t.value})}case u.T.DOLLAR:if(e){if(this.expectToken(u.T.DOLLAR),this._lexer.token.kind===u.T.NAME){const e=this._lexer.token.value;throw(0,r.h)(this._lexer.source,t.start,`Unexpected variable "$${e}" in constant value.`)}throw this.unexpected(t)}return this.parseVariable();default:throw this.unexpected()}}parseConstValueLiteral(){return this.parseValueLiteral(!0)}parseStringLiteral(){const e=this._lexer.token;return this._lexer.advance(),this.node(e,{kind:a.h.STRING,value:e.value,block:e.kind===u.T.BLOCK_STRING})}parseList(e){return this.node(this._lexer.token,{kind:a.h.LIST,values:this.any(u.T.BRACKET_L,(()=>this.parseValueLiteral(e)),u.T.BRACKET_R)})}parseObject(e){return this.node(this._lexer.token,{kind:a.h.OBJECT,fields:this.any(u.T.BRACE_L,(()=>this.parseObjectField(e)),u.T.BRACE_R)})}parseObjectField(e){const t=this._lexer.token,n=this.parseName();return this.expectToken(u.T.COLON),this.node(t,{kind:a.h.OBJECT_FIELD,name:n,value:this.parseValueLiteral(e)})}parseDirectives(e){const t=[];for(;this.peek(u.T.AT);)t.push(this.parseDirective(e));return t}parseConstDirectives(){return this.parseDirectives(!0)}parseDirective(e){const t=this._lexer.token;return this.expectToken(u.T.AT),this.node(t,{kind:a.h.DIRECTIVE,name:this.parseName(),arguments:this.parseArguments(e)})}parseTypeReference(){const e=this._lexer.token;let t;if(this.expectOptionalToken(u.T.BRACKET_L)){const n=this.parseTypeReference();this.expectToken(u.T.BRACKET_R),t=this.node(e,{kind:a.h.LIST_TYPE,type:n})}else t=this.parseNamedType();return this.expectOptionalToken(u.T.BANG)?this.node(e,{kind:a.h.NON_NULL_TYPE,type:t}):t}parseNamedType(){return this.node(this._lexer.token,{kind:a.h.NAMED_TYPE,name:this.parseName()})}peekDescription(){return this.peek(u.T.STRING)||this.peek(u.T.BLOCK_STRING)}parseDescription(){if(this.peekDescription())return this.parseStringLiteral()}parseSchemaDefinition(){const e=this._lexer.token,t=this.parseDescription();this.expectKeyword("schema");const n=this.parseConstDirectives(),r=this.many(u.T.BRACE_L,this.parseOperationTypeDefinition,u.T.BRACE_R);return this.node(e,{kind:a.h.SCHEMA_DEFINITION,description:t,directives:n,operationTypes:r})}parseOperationTypeDefinition(){const e=this._lexer.token,t=this.parseOperationType();this.expectToken(u.T.COLON);const n=this.parseNamedType();return this.node(e,{kind:a.h.OPERATION_TYPE_DEFINITION,operation:t,type:n})}parseScalarTypeDefinition(){const e=this._lexer.token,t=this.parseDescription();this.expectKeyword("scalar");const n=this.parseName(),r=this.parseConstDirectives();return this.node(e,{kind:a.h.SCALAR_TYPE_DEFINITION,description:t,name:n,directives:r})}parseObjectTypeDefinition(){const e=this._lexer.token,t=this.parseDescription();this.expectKeyword("type");const n=this.parseName(),r=this.parseImplementsInterfaces(),i=this.parseConstDirectives(),o=this.parseFieldsDefinition();return this.node(e,{kind:a.h.OBJECT_TYPE_DEFINITION,description:t,name:n,interfaces:r,directives:i,fields:o})}parseImplementsInterfaces(){return this.expectOptionalKeyword("implements")?this.delimitedMany(u.T.AMP,this.parseNamedType):[]}parseFieldsDefinition(){return this.optionalMany(u.T.BRACE_L,this.parseFieldDefinition,u.T.BRACE_R)}parseFieldDefinition(){const e=this._lexer.token,t=this.parseDescription(),n=this.parseName(),r=this.parseArgumentDefs();this.expectToken(u.T.COLON);const i=this.parseTypeReference(),o=this.parseConstDirectives();return this.node(e,{kind:a.h.FIELD_DEFINITION,description:t,name:n,arguments:r,type:i,directives:o})}parseArgumentDefs(){return this.optionalMany(u.T.PAREN_L,this.parseInputValueDef,u.T.PAREN_R)}parseInputValueDef(){const e=this._lexer.token,t=this.parseDescription(),n=this.parseName();this.expectToken(u.T.COLON);const r=this.parseTypeReference();let i;this.expectOptionalToken(u.T.EQUALS)&&(i=this.parseConstValueLiteral());const o=this.parseConstDirectives();return this.node(e,{kind:a.h.INPUT_VALUE_DEFINITION,description:t,name:n,type:r,defaultValue:i,directives:o})}parseInterfaceTypeDefinition(){const e=this._lexer.token,t=this.parseDescription();this.expectKeyword("interface");const n=this.parseName(),r=this.parseImplementsInterfaces(),i=this.parseConstDirectives(),o=this.parseFieldsDefinition();return this.node(e,{kind:a.h.INTERFACE_TYPE_DEFINITION,description:t,name:n,interfaces:r,directives:i,fields:o})}parseUnionTypeDefinition(){const e=this._lexer.token,t=this.parseDescription();this.expectKeyword("union");const n=this.parseName(),r=this.parseConstDirectives(),i=this.parseUnionMemberTypes();return this.node(e,{kind:a.h.UNION_TYPE_DEFINITION,description:t,name:n,directives:r,types:i})}parseUnionMemberTypes(){return this.expectOptionalToken(u.T.EQUALS)?this.delimitedMany(u.T.PIPE,this.parseNamedType):[]}parseEnumTypeDefinition(){const e=this._lexer.token,t=this.parseDescription();this.expectKeyword("enum");const n=this.parseName(),r=this.parseConstDirectives(),i=this.parseEnumValuesDefinition();return this.node(e,{kind:a.h.ENUM_TYPE_DEFINITION,description:t,name:n,directives:r,values:i})}parseEnumValuesDefinition(){return this.optionalMany(u.T.BRACE_L,this.parseEnumValueDefinition,u.T.BRACE_R)}parseEnumValueDefinition(){const e=this._lexer.token,t=this.parseDescription(),n=this.parseEnumValueName(),r=this.parseConstDirectives();return this.node(e,{kind:a.h.ENUM_VALUE_DEFINITION,description:t,name:n,directives:r})}parseEnumValueName(){if("true"===this._lexer.token.value||"false"===this._lexer.token.value||"null"===this._lexer.token.value)throw(0,r.h)(this._lexer.source,this._lexer.token.start,`${m(this._lexer.token)} is reserved and cannot be used for an enum value.`);return this.parseName()}parseInputObjectTypeDefinition(){const e=this._lexer.token,t=this.parseDescription();this.expectKeyword("input");const n=this.parseName(),r=this.parseConstDirectives(),i=this.parseInputFieldsDefinition();return this.node(e,{kind:a.h.INPUT_OBJECT_TYPE_DEFINITION,description:t,name:n,directives:r,fields:i})}parseInputFieldsDefinition(){return this.optionalMany(u.T.BRACE_L,this.parseInputValueDef,u.T.BRACE_R)}parseTypeSystemExtension(){const e=this._lexer.lookahead();if(e.kind===u.T.NAME)switch(e.value){case"schema":return this.parseSchemaExtension();case"scalar":return this.parseScalarTypeExtension();case"type":return this.parseObjectTypeExtension();case"interface":return this.parseInterfaceTypeExtension();case"union":return this.parseUnionTypeExtension();case"enum":return this.parseEnumTypeExtension();case"input":return this.parseInputObjectTypeExtension()}throw this.unexpected(e)}parseSchemaExtension(){const e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("schema");const t=this.parseConstDirectives(),n=this.optionalMany(u.T.BRACE_L,this.parseOperationTypeDefinition,u.T.BRACE_R);if(0===t.length&&0===n.length)throw this.unexpected();return this.node(e,{kind:a.h.SCHEMA_EXTENSION,directives:t,operationTypes:n})}parseScalarTypeExtension(){const e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("scalar");const t=this.parseName(),n=this.parseConstDirectives();if(0===n.length)throw this.unexpected();return this.node(e,{kind:a.h.SCALAR_TYPE_EXTENSION,name:t,directives:n})}parseObjectTypeExtension(){const e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("type");const t=this.parseName(),n=this.parseImplementsInterfaces(),r=this.parseConstDirectives(),i=this.parseFieldsDefinition();if(0===n.length&&0===r.length&&0===i.length)throw this.unexpected();return this.node(e,{kind:a.h.OBJECT_TYPE_EXTENSION,name:t,interfaces:n,directives:r,fields:i})}parseInterfaceTypeExtension(){const e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("interface");const t=this.parseName(),n=this.parseImplementsInterfaces(),r=this.parseConstDirectives(),i=this.parseFieldsDefinition();if(0===n.length&&0===r.length&&0===i.length)throw this.unexpected();return this.node(e,{kind:a.h.INTERFACE_TYPE_EXTENSION,name:t,interfaces:n,directives:r,fields:i})}parseUnionTypeExtension(){const e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("union");const t=this.parseName(),n=this.parseConstDirectives(),r=this.parseUnionMemberTypes();if(0===n.length&&0===r.length)throw this.unexpected();return this.node(e,{kind:a.h.UNION_TYPE_EXTENSION,name:t,directives:n,types:r})}parseEnumTypeExtension(){const e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("enum");const t=this.parseName(),n=this.parseConstDirectives(),r=this.parseEnumValuesDefinition();if(0===n.length&&0===r.length)throw this.unexpected();return this.node(e,{kind:a.h.ENUM_TYPE_EXTENSION,name:t,directives:n,values:r})}parseInputObjectTypeExtension(){const e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("input");const t=this.parseName(),n=this.parseConstDirectives(),r=this.parseInputFieldsDefinition();if(0===n.length&&0===r.length)throw this.unexpected();return this.node(e,{kind:a.h.INPUT_OBJECT_TYPE_EXTENSION,name:t,directives:n,fields:r})}parseDirectiveDefinition(){const e=this._lexer.token,t=this.parseDescription();this.expectKeyword("directive"),this.expectToken(u.T.AT);const n=this.parseName(),r=this.parseArgumentDefs(),i=this.expectOptionalKeyword("repeatable");this.expectKeyword("on");const o=this.parseDirectiveLocations();return this.node(e,{kind:a.h.DIRECTIVE_DEFINITION,description:t,name:n,arguments:r,repeatable:i,locations:o})}parseDirectiveLocations(){return this.delimitedMany(u.T.PIPE,this.parseDirectiveLocation)}parseDirectiveLocation(){const e=this._lexer.token,t=this.parseName();if(Object.prototype.hasOwnProperty.call(o.B,t.value))return t;throw this.unexpected(e)}node(e,t){var n;return!0!==(null===(n=this._options)||void 0===n?void 0:n.noLocation)&&(t.loc=new i.Ye(e,this._lexer.lastToken,this._lexer.source)),t}peek(e){return this._lexer.token.kind===e}expectToken(e){const t=this._lexer.token;if(t.kind===e)return this._lexer.advance(),t;throw(0,r.h)(this._lexer.source,t.start,`Expected ${g(e)}, found ${m(t)}.`)}expectOptionalToken(e){return this._lexer.token.kind===e&&(this._lexer.advance(),!0)}expectKeyword(e){const t=this._lexer.token;if(t.kind!==u.T.NAME||t.value!==e)throw(0,r.h)(this._lexer.source,t.start,`Expected "${e}", found ${m(t)}.`);this._lexer.advance()}expectOptionalKeyword(e){const t=this._lexer.token;return t.kind===u.T.NAME&&t.value===e&&(this._lexer.advance(),!0)}unexpected(e){const t=null!=e?e:this._lexer.token;return(0,r.h)(this._lexer.source,t.start,`Unexpected ${m(t)}.`)}any(e,t,n){this.expectToken(e);const r=[];for(;!this.expectOptionalToken(n);)r.push(t.call(this));return r}optionalMany(e,t,n){if(this.expectOptionalToken(e)){const e=[];do{e.push(t.call(this))}while(!this.expectOptionalToken(n));return e}return[]}many(e,t,n){this.expectToken(e);const r=[];do{r.push(t.call(this))}while(!this.expectOptionalToken(n));return r}delimitedMany(e,t){this.expectOptionalToken(e);const n=[];do{n.push(t.call(this))}while(this.expectOptionalToken(e));return n}}function m(e){const t=e.value;return g(e.kind)+(null!=t?` "${t}"`:"")}function g(e){return(0,s.u)(e)?`"${e}"`:e}},9615:function(e,t,n){"use strict";n.d(t,{D$:function(){return p},G4:function(){return c},Ir:function(){return i},Of:function(){return l},VB:function(){return u},Wk:function(){return o},aU:function(){return f},nr:function(){return s},pO:function(){return a},zT:function(){return d}});var r=n(3830);function i(e){return o(e)||c(e)||f(e)}function o(e){return e.kind===r.h.OPERATION_DEFINITION||e.kind===r.h.FRAGMENT_DEFINITION}function a(e){return e.kind===r.h.FIELD||e.kind===r.h.FRAGMENT_SPREAD||e.kind===r.h.INLINE_FRAGMENT}function s(e){return e.kind===r.h.VARIABLE||e.kind===r.h.INT||e.kind===r.h.FLOAT||e.kind===r.h.STRING||e.kind===r.h.BOOLEAN||e.kind===r.h.NULL||e.kind===r.h.ENUM||e.kind===r.h.LIST||e.kind===r.h.OBJECT}function l(e){return s(e)&&(e.kind===r.h.LIST?e.values.some(l):e.kind===r.h.OBJECT?e.fields.some((e=>l(e.value))):e.kind!==r.h.VARIABLE)}function u(e){return e.kind===r.h.NAMED_TYPE||e.kind===r.h.LIST_TYPE||e.kind===r.h.NON_NULL_TYPE}function c(e){return e.kind===r.h.SCHEMA_DEFINITION||d(e)||e.kind===r.h.DIRECTIVE_DEFINITION}function d(e){return e.kind===r.h.SCALAR_TYPE_DEFINITION||e.kind===r.h.OBJECT_TYPE_DEFINITION||e.kind===r.h.INTERFACE_TYPE_DEFINITION||e.kind===r.h.UNION_TYPE_DEFINITION||e.kind===r.h.ENUM_TYPE_DEFINITION||e.kind===r.h.INPUT_OBJECT_TYPE_DEFINITION}function f(e){return e.kind===r.h.SCHEMA_EXTENSION||p(e)}function p(e){return e.kind===r.h.SCALAR_TYPE_EXTENSION||e.kind===r.h.OBJECT_TYPE_EXTENSION||e.kind===r.h.INTERFACE_TYPE_EXTENSION||e.kind===r.h.UNION_TYPE_EXTENSION||e.kind===r.h.ENUM_TYPE_EXTENSION||e.kind===r.h.INPUT_OBJECT_TYPE_EXTENSION}},7026:function(e,t,n){"use strict";n.d(t,{Q:function(){return i},z:function(){return o}});var r=n(3302);function i(e){return o(e.source,(0,r.k)(e.source,e.start))}function o(e,t){const n=e.locationOffset.column-1,r="".padStart(n)+e.body,i=t.line-1,o=e.locationOffset.line-1,s=t.line+o,l=1===t.line?n:0,u=t.column+l,c=`${e.name}:${s}:${u}\n`,d=r.split(/\r\n|[\n\r]/g),f=d[i];if(f.length>120){const e=Math.floor(u/80),t=u%80,n=[];for(let e=0;e["|",e])),["|","^".padStart(t)],["|",n[e+1]]])}return c+a([[s-1+" |",d[i-1]],[`${s} |`,f],["|","^".padStart(u)],[`${s+1} |`,d[i+1]]])}function a(e){const t=e.filter((([e,t])=>void 0!==t)),n=Math.max(...t.map((([e])=>e.length)));return t.map((([e,t])=>e.padStart(n)+(t?" "+t:""))).join("\n")}},5895:function(e,t,n){"use strict";n.d(t,{S:function(){return l}});var r=n(6303);const i=/[\x00-\x1f\x22\x5c\x7f-\x9f]/g;function o(e){return a[e.charCodeAt(0)]}const a=["\\u0000","\\u0001","\\u0002","\\u0003","\\u0004","\\u0005","\\u0006","\\u0007","\\b","\\t","\\n","\\u000B","\\f","\\r","\\u000E","\\u000F","\\u0010","\\u0011","\\u0012","\\u0013","\\u0014","\\u0015","\\u0016","\\u0017","\\u0018","\\u0019","\\u001A","\\u001B","\\u001C","\\u001D","\\u001E","\\u001F","","",'\\"',"","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","\\\\","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","\\u007F","\\u0080","\\u0081","\\u0082","\\u0083","\\u0084","\\u0085","\\u0086","\\u0087","\\u0088","\\u0089","\\u008A","\\u008B","\\u008C","\\u008D","\\u008E","\\u008F","\\u0090","\\u0091","\\u0092","\\u0093","\\u0094","\\u0095","\\u0096","\\u0097","\\u0098","\\u0099","\\u009A","\\u009B","\\u009C","\\u009D","\\u009E","\\u009F"];var s=n(9685);function l(e){return(0,s.Vn)(e,u)}const u={Name:{leave:e=>e.value},Variable:{leave:e=>"$"+e.name},Document:{leave:e=>c(e.definitions,"\n\n")},OperationDefinition:{leave(e){const t=f("(",c(e.variableDefinitions,", "),")"),n=c([e.operation,c([e.name,t]),c(e.directives," ")]," ");return("query"===n?"":n+" ")+e.selectionSet}},VariableDefinition:{leave:({variable:e,type:t,defaultValue:n,directives:r})=>e+": "+t+f(" = ",n)+f(" ",c(r," "))},SelectionSet:{leave:({selections:e})=>d(e)},Field:{leave({alias:e,name:t,arguments:n,directives:r,selectionSet:i}){const o=f("",e,": ")+t;let a=o+f("(",c(n,", "),")");return a.length>80&&(a=o+f("(\n",p(c(n,"\n")),"\n)")),c([a,c(r," "),i]," ")}},Argument:{leave:({name:e,value:t})=>e+": "+t},FragmentSpread:{leave:({name:e,directives:t})=>"..."+e+f(" ",c(t," "))},InlineFragment:{leave:({typeCondition:e,directives:t,selectionSet:n})=>c(["...",f("on ",e),c(t," "),n]," ")},FragmentDefinition:{leave:({name:e,typeCondition:t,variableDefinitions:n,directives:r,selectionSet:i})=>`fragment ${e}${f("(",c(n,", "),")")} on ${t} ${f("",c(r," ")," ")}`+i},IntValue:{leave:({value:e})=>e},FloatValue:{leave:({value:e})=>e},StringValue:{leave:({value:e,block:t})=>t?(0,r.LZ)(e):`"${e.replace(i,o)}"`},BooleanValue:{leave:({value:e})=>e?"true":"false"},NullValue:{leave:()=>"null"},EnumValue:{leave:({value:e})=>e},ListValue:{leave:({values:e})=>"["+c(e,", ")+"]"},ObjectValue:{leave:({fields:e})=>"{"+c(e,", ")+"}"},ObjectField:{leave:({name:e,value:t})=>e+": "+t},Directive:{leave:({name:e,arguments:t})=>"@"+e+f("(",c(t,", "),")")},NamedType:{leave:({name:e})=>e},ListType:{leave:({type:e})=>"["+e+"]"},NonNullType:{leave:({type:e})=>e+"!"},SchemaDefinition:{leave:({description:e,directives:t,operationTypes:n})=>f("",e,"\n")+c(["schema",c(t," "),d(n)]," ")},OperationTypeDefinition:{leave:({operation:e,type:t})=>e+": "+t},ScalarTypeDefinition:{leave:({description:e,name:t,directives:n})=>f("",e,"\n")+c(["scalar",t,c(n," ")]," ")},ObjectTypeDefinition:{leave:({description:e,name:t,interfaces:n,directives:r,fields:i})=>f("",e,"\n")+c(["type",t,f("implements ",c(n," & ")),c(r," "),d(i)]," ")},FieldDefinition:{leave:({description:e,name:t,arguments:n,type:r,directives:i})=>f("",e,"\n")+t+(h(n)?f("(\n",p(c(n,"\n")),"\n)"):f("(",c(n,", "),")"))+": "+r+f(" ",c(i," "))},InputValueDefinition:{leave:({description:e,name:t,type:n,defaultValue:r,directives:i})=>f("",e,"\n")+c([t+": "+n,f("= ",r),c(i," ")]," ")},InterfaceTypeDefinition:{leave:({description:e,name:t,interfaces:n,directives:r,fields:i})=>f("",e,"\n")+c(["interface",t,f("implements ",c(n," & ")),c(r," "),d(i)]," ")},UnionTypeDefinition:{leave:({description:e,name:t,directives:n,types:r})=>f("",e,"\n")+c(["union",t,c(n," "),f("= ",c(r," | "))]," ")},EnumTypeDefinition:{leave:({description:e,name:t,directives:n,values:r})=>f("",e,"\n")+c(["enum",t,c(n," "),d(r)]," ")},EnumValueDefinition:{leave:({description:e,name:t,directives:n})=>f("",e,"\n")+c([t,c(n," ")]," ")},InputObjectTypeDefinition:{leave:({description:e,name:t,directives:n,fields:r})=>f("",e,"\n")+c(["input",t,c(n," "),d(r)]," ")},DirectiveDefinition:{leave:({description:e,name:t,arguments:n,repeatable:r,locations:i})=>f("",e,"\n")+"directive @"+t+(h(n)?f("(\n",p(c(n,"\n")),"\n)"):f("(",c(n,", "),")"))+(r?" repeatable":"")+" on "+c(i," | ")},SchemaExtension:{leave:({directives:e,operationTypes:t})=>c(["extend schema",c(e," "),d(t)]," ")},ScalarTypeExtension:{leave:({name:e,directives:t})=>c(["extend scalar",e,c(t," ")]," ")},ObjectTypeExtension:{leave:({name:e,interfaces:t,directives:n,fields:r})=>c(["extend type",e,f("implements ",c(t," & ")),c(n," "),d(r)]," ")},InterfaceTypeExtension:{leave:({name:e,interfaces:t,directives:n,fields:r})=>c(["extend interface",e,f("implements ",c(t," & ")),c(n," "),d(r)]," ")},UnionTypeExtension:{leave:({name:e,directives:t,types:n})=>c(["extend union",e,c(t," "),f("= ",c(n," | "))]," ")},EnumTypeExtension:{leave:({name:e,directives:t,values:n})=>c(["extend enum",e,c(t," "),d(n)]," ")},InputObjectTypeExtension:{leave:({name:e,directives:t,fields:n})=>c(["extend input",e,c(t," "),d(n)]," ")}};function c(e,t=""){var n;return null!==(n=null==e?void 0:e.filter((e=>e)).join(t))&&void 0!==n?n:""}function d(e){return f("{\n",p(c(e,"\n")),"\n}")}function f(e,t,n=""){return null!=t&&""!==t?e+t+n:""}function p(e){return f(" ",e.replace(/\n/g,"\n "))}function h(e){var t;return null!==(t=null==e?void 0:e.some((e=>e.includes("\n"))))&&void 0!==t&&t}},4680:function(e,t,n){"use strict";n.d(t,{H:function(){return a},T:function(){return s}});var r=n(1172),i=n(5648),o=n(1513);class a{constructor(e,t="GraphQL request",n={line:1,column:1}){"string"==typeof e||(0,r.a)(!1,`Body must be a string. Received: ${(0,i.X)(e)}.`),this.body=e,this.name=t,this.locationOffset=n,this.locationOffset.line>0||(0,r.a)(!1,"line in locationOffset is 1-indexed and must be positive."),this.locationOffset.column>0||(0,r.a)(!1,"column in locationOffset is 1-indexed and must be positive.")}get[Symbol.toStringTag](){return"Source"}}function s(e){return(0,o.n)(e,a)}},5685:function(e,t,n){"use strict";let r;n.d(t,{T:function(){return r}}),function(e){e.SOF="",e.EOF="",e.BANG="!",e.DOLLAR="$",e.AMP="&",e.PAREN_L="(",e.PAREN_R=")",e.SPREAD="...",e.COLON=":",e.EQUALS="=",e.AT="@",e.BRACKET_L="[",e.BRACKET_R="]",e.BRACE_L="{",e.PIPE="|",e.BRACE_R="}",e.NAME="Name",e.INT="Int",e.FLOAT="Float",e.STRING="String",e.BLOCK_STRING="BlockString",e.COMMENT="Comment"}(r||(r={}))},9685:function(e,t,n){"use strict";n.d(t,{$_:function(){return s},CK:function(){return d},Eu:function(){return c},Vn:function(){return l},j1:function(){return u}});var r=n(1172),i=n(5648),o=n(3526),a=n(3830);const s=Object.freeze({});function l(e,t,n=o.h8){const l=new Map;for(const e of Object.values(a.h))l.set(e,c(t,e));let u,d,f,p=Array.isArray(e),h=[e],m=-1,g=[],v=e;const y=[],b=[];do{m++;const e=m===h.length,a=e&&0!==g.length;if(e){if(d=0===b.length?void 0:y[y.length-1],v=f,f=b.pop(),a)if(p){v=v.slice();let e=0;for(const[t,n]of g){const r=t-e;null===n?(v.splice(r,1),e++):v[r]=n}}else{v=Object.defineProperties({},Object.getOwnPropertyDescriptors(v));for(const[e,t]of g)v[e]=t}m=u.index,h=u.keys,g=u.edits,p=u.inArray,u=u.prev}else if(f){if(d=p?m:h[m],v=f[d],null==v)continue;y.push(d)}let c;if(!Array.isArray(v)){var E,T;(0,o.UG)(v)||(0,r.a)(!1,`Invalid AST Node: ${(0,i.X)(v)}.`);const n=e?null===(E=l.get(v.kind))||void 0===E?void 0:E.leave:null===(T=l.get(v.kind))||void 0===T?void 0:T.enter;if(c=null==n?void 0:n.call(t,v,d,f,y,b),c===s)break;if(!1===c){if(!e){y.pop();continue}}else if(void 0!==c&&(g.push([d,c]),!e)){if(!(0,o.UG)(c)){y.pop();continue}v=c}}var w;void 0===c&&a&&g.push([d,v]),e?y.pop():(u={inArray:p,index:m,keys:h,edits:g,prev:u},p=Array.isArray(v),h=p?v:null!==(w=n[v.kind])&&void 0!==w?w:[],m=-1,g=[],f&&b.push(f),f=v)}while(void 0!==u);return 0!==g.length?g[g.length-1][1]:e}function u(e){const t=new Array(e.length).fill(null),n=Object.create(null);for(const r of Object.values(a.h)){let i=!1;const o=new Array(e.length).fill(void 0),a=new Array(e.length).fill(void 0);for(let t=0;tl((0,v.M)(e,t)),this.extensions=(0,p.u)(e.extensions),this.astNode=e.astNode,this.extensionASTNodes=null!==(s=e.extensionASTNodes)&&void 0!==s?s:[],null==e.specifiedByURL||"string"==typeof e.specifiedByURL||(0,r.a)(!1,`${this.name} must provide "specifiedByURL" as a string, but got: ${(0,a.X)(e.specifiedByURL)}.`),null==e.serialize||"function"==typeof e.serialize||(0,r.a)(!1,`${this.name} must provide "serialize" function. If this custom Scalar is also used as an input type, ensure "parseValue" and "parseLiteral" functions are also provided.`),e.parseLiteral&&("function"==typeof e.parseValue&&"function"==typeof e.parseLiteral||(0,r.a)(!1,`${this.name} must provide both "parseValue" and "parseLiteral" functions.`))}get[Symbol.toStringTag](){return"GraphQLScalarType"}toConfig(){return{name:this.name,description:this.description,specifiedByURL:this.specifiedByURL,serialize:this.serialize,parseValue:this.parseValue,parseLiteral:this.parseLiteral,extensions:this.extensions,astNode:this.astNode,extensionASTNodes:this.extensionASTNodes}}toString(){return this.name}toJSON(){return this.toString()}}class ae{constructor(e){var t;this.name=(0,y.i)(e.name),this.description=e.description,this.isTypeOf=e.isTypeOf,this.extensions=(0,p.u)(e.extensions),this.astNode=e.astNode,this.extensionASTNodes=null!==(t=e.extensionASTNodes)&&void 0!==t?t:[],this._fields=()=>le(e),this._interfaces=()=>se(e),null==e.isTypeOf||"function"==typeof e.isTypeOf||(0,r.a)(!1,`${this.name} must provide "isTypeOf" as a function, but got: ${(0,a.X)(e.isTypeOf)}.`)}get[Symbol.toStringTag](){return"GraphQLObjectType"}getFields(){return"function"==typeof this._fields&&(this._fields=this._fields()),this._fields}getInterfaces(){return"function"==typeof this._interfaces&&(this._interfaces=this._interfaces()),this._interfaces}toConfig(){return{name:this.name,description:this.description,interfaces:this.getInterfaces(),fields:de(this.getFields()),isTypeOf:this.isTypeOf,extensions:this.extensions,astNode:this.astNode,extensionASTNodes:this.extensionASTNodes}}toString(){return this.name}toJSON(){return this.toString()}}function se(e){var t;const n=re(null!==(t=e.interfaces)&&void 0!==t?t:[]);return Array.isArray(n)||(0,r.a)(!1,`${e.name} interfaces must be an Array or a function which returns an Array.`),n}function le(e){const t=ie(e.fields);return ce(t)||(0,r.a)(!1,`${e.name} fields must be an object with field names as keys or a function which returns such an object.`),(0,d.j)(t,((t,n)=>{var i;ce(t)||(0,r.a)(!1,`${e.name}.${n} field config must be an object.`),null==t.resolve||"function"==typeof t.resolve||(0,r.a)(!1,`${e.name}.${n} field resolver must be a function if provided, but got: ${(0,a.X)(t.resolve)}.`);const o=null!==(i=t.args)&&void 0!==i?i:{};return ce(o)||(0,r.a)(!1,`${e.name}.${n} args must be an object with argument names as keys.`),{name:(0,y.i)(n),description:t.description,type:t.type,args:ue(o),resolve:t.resolve,subscribe:t.subscribe,deprecationReason:t.deprecationReason,extensions:(0,p.u)(t.extensions),astNode:t.astNode}}))}function ue(e){return Object.entries(e).map((([e,t])=>({name:(0,y.i)(e),description:t.description,type:t.type,defaultValue:t.defaultValue,deprecationReason:t.deprecationReason,extensions:(0,p.u)(t.extensions),astNode:t.astNode})))}function ce(e){return(0,l.y)(e)&&!Array.isArray(e)}function de(e){return(0,d.j)(e,(e=>({description:e.description,type:e.type,args:fe(e.args),resolve:e.resolve,subscribe:e.subscribe,deprecationReason:e.deprecationReason,extensions:e.extensions,astNode:e.astNode})))}function fe(e){return(0,c.w)(e,(e=>e.name),(e=>({description:e.description,type:e.type,defaultValue:e.defaultValue,deprecationReason:e.deprecationReason,extensions:e.extensions,astNode:e.astNode})))}function pe(e){return R(e.type)&&void 0===e.defaultValue}class he{constructor(e){var t;this.name=(0,y.i)(e.name),this.description=e.description,this.resolveType=e.resolveType,this.extensions=(0,p.u)(e.extensions),this.astNode=e.astNode,this.extensionASTNodes=null!==(t=e.extensionASTNodes)&&void 0!==t?t:[],this._fields=le.bind(void 0,e),this._interfaces=se.bind(void 0,e),null==e.resolveType||"function"==typeof e.resolveType||(0,r.a)(!1,`${this.name} must provide "resolveType" as a function, but got: ${(0,a.X)(e.resolveType)}.`)}get[Symbol.toStringTag](){return"GraphQLInterfaceType"}getFields(){return"function"==typeof this._fields&&(this._fields=this._fields()),this._fields}getInterfaces(){return"function"==typeof this._interfaces&&(this._interfaces=this._interfaces()),this._interfaces}toConfig(){return{name:this.name,description:this.description,interfaces:this.getInterfaces(),fields:de(this.getFields()),resolveType:this.resolveType,extensions:this.extensions,astNode:this.astNode,extensionASTNodes:this.extensionASTNodes}}toString(){return this.name}toJSON(){return this.toString()}}class me{constructor(e){var t;this.name=(0,y.i)(e.name),this.description=e.description,this.resolveType=e.resolveType,this.extensions=(0,p.u)(e.extensions),this.astNode=e.astNode,this.extensionASTNodes=null!==(t=e.extensionASTNodes)&&void 0!==t?t:[],this._types=ge.bind(void 0,e),null==e.resolveType||"function"==typeof e.resolveType||(0,r.a)(!1,`${this.name} must provide "resolveType" as a function, but got: ${(0,a.X)(e.resolveType)}.`)}get[Symbol.toStringTag](){return"GraphQLUnionType"}getTypes(){return"function"==typeof this._types&&(this._types=this._types()),this._types}toConfig(){return{name:this.name,description:this.description,types:this.getTypes(),resolveType:this.resolveType,extensions:this.extensions,astNode:this.astNode,extensionASTNodes:this.extensionASTNodes}}toString(){return this.name}toJSON(){return this.toString()}}function ge(e){const t=re(e.types);return Array.isArray(t)||(0,r.a)(!1,`Must provide Array of types or a function which returns such an array for Union ${e.name}.`),t}class ve{constructor(e){var t,n,i;this.name=(0,y.i)(e.name),this.description=e.description,this.extensions=(0,p.u)(e.extensions),this.astNode=e.astNode,this.extensionASTNodes=null!==(t=e.extensionASTNodes)&&void 0!==t?t:[],this._values=(n=this.name,ce(i=e.values)||(0,r.a)(!1,`${n} values must be an object with value names as keys.`),Object.entries(i).map((([e,t])=>(ce(t)||(0,r.a)(!1,`${n}.${e} must refer to an object with a "value" key representing an internal value but got: ${(0,a.X)(t)}.`),{name:(0,y.g)(e),description:t.description,value:void 0!==t.value?t.value:e,deprecationReason:t.deprecationReason,extensions:(0,p.u)(t.extensions),astNode:t.astNode})))),this._valueLookup=new Map(this._values.map((e=>[e.value,e]))),this._nameLookup=(0,u.P)(this._values,(e=>e.name))}get[Symbol.toStringTag](){return"GraphQLEnumType"}getValues(){return this._values}getValue(e){return this._nameLookup[e]}serialize(e){const t=this._valueLookup.get(e);if(void 0===t)throw new h.__(`Enum "${this.name}" cannot represent value: ${(0,a.X)(e)}`);return t.name}parseValue(e){if("string"!=typeof e){const t=(0,a.X)(e);throw new h.__(`Enum "${this.name}" cannot represent non-string value: ${t}.`+ye(this,t))}const t=this.getValue(e);if(null==t)throw new h.__(`Value "${e}" does not exist in "${this.name}" enum.`+ye(this,e));return t.value}parseLiteral(e,t){if(e.kind!==m.h.ENUM){const t=(0,g.S)(e);throw new h.__(`Enum "${this.name}" cannot represent non-enum value: ${t}.`+ye(this,t),{nodes:e})}const n=this.getValue(e.value);if(null==n){const t=(0,g.S)(e);throw new h.__(`Value "${t}" does not exist in "${this.name}" enum.`+ye(this,t),{nodes:e})}return n.value}toConfig(){const e=(0,c.w)(this.getValues(),(e=>e.name),(e=>({description:e.description,value:e.value,deprecationReason:e.deprecationReason,extensions:e.extensions,astNode:e.astNode})));return{name:this.name,description:this.description,values:e,extensions:this.extensions,astNode:this.astNode,extensionASTNodes:this.extensionASTNodes}}toString(){return this.name}toJSON(){return this.toString()}}function ye(e,t){const n=e.getValues().map((e=>e.name)),r=(0,f.D)(t,n);return(0,i.l)("the enum value",r)}class be{constructor(e){var t;this.name=(0,y.i)(e.name),this.description=e.description,this.extensions=(0,p.u)(e.extensions),this.astNode=e.astNode,this.extensionASTNodes=null!==(t=e.extensionASTNodes)&&void 0!==t?t:[],this._fields=Ee.bind(void 0,e)}get[Symbol.toStringTag](){return"GraphQLInputObjectType"}getFields(){return"function"==typeof this._fields&&(this._fields=this._fields()),this._fields}toConfig(){const e=(0,d.j)(this.getFields(),(e=>({description:e.description,type:e.type,defaultValue:e.defaultValue,deprecationReason:e.deprecationReason,extensions:e.extensions,astNode:e.astNode})));return{name:this.name,description:this.description,fields:e,extensions:this.extensions,astNode:this.astNode,extensionASTNodes:this.extensionASTNodes}}toString(){return this.name}toJSON(){return this.toString()}}function Ee(e){const t=ie(e.fields);return ce(t)||(0,r.a)(!1,`${e.name} fields must be an object with field names as keys or a function which returns such an object.`),(0,d.j)(t,((t,n)=>(!("resolve"in t)||(0,r.a)(!1,`${e.name}.${n} field has a resolve property, but Input Types cannot define resolvers.`),{name:(0,y.i)(n),description:t.description,type:t.type,defaultValue:t.defaultValue,deprecationReason:t.deprecationReason,extensions:(0,p.u)(t.extensions),astNode:t.astNode})))}function Te(e){return R(e.type)&&void 0===e.defaultValue}},5946:function(e,t,n){"use strict";n.d(t,{CO:function(){return p},NZ:function(){return h},QE:function(){return g},SY:function(){return v},V4:function(){return E},Yf:function(){return m},df:function(){return b},fg:function(){return y},wX:function(){return f},xg:function(){return T}});var r=n(1172),i=n(5648),o=n(1513),a=n(1315),s=n(1140),l=n(3140),u=n(3228),c=n(755),d=n(1774);function f(e){return(0,o.n)(e,h)}function p(e){if(!f(e))throw new Error(`Expected ${(0,i.X)(e)} to be a GraphQL directive.`);return e}class h{constructor(e){var t,n;this.name=(0,u.i)(e.name),this.description=e.description,this.locations=e.locations,this.isRepeatable=null!==(t=e.isRepeatable)&&void 0!==t&&t,this.extensions=(0,s.u)(e.extensions),this.astNode=e.astNode,Array.isArray(e.locations)||(0,r.a)(!1,`@${e.name} locations must be an Array.`);const i=null!==(n=e.args)&&void 0!==n?n:{};(0,a.y)(i)&&!Array.isArray(i)||(0,r.a)(!1,`@${e.name} args must be an object with argument names as keys.`),this.args=(0,c.WO)(i)}get[Symbol.toStringTag](){return"GraphQLDirective"}toConfig(){return{name:this.name,description:this.description,locations:this.locations,args:(0,c.DM)(this.args),isRepeatable:this.isRepeatable,extensions:this.extensions,astNode:this.astNode}}toString(){return"@"+this.name}toJSON(){return this.toString()}}const m=new h({name:"include",description:"Directs the executor to include this field or fragment only when the `if` argument is true.",locations:[l.B.FIELD,l.B.FRAGMENT_SPREAD,l.B.INLINE_FRAGMENT],args:{if:{type:new c.bM(d.EZ),description:"Included when true."}}}),g=new h({name:"skip",description:"Directs the executor to skip this field or fragment when the `if` argument is true.",locations:[l.B.FIELD,l.B.FRAGMENT_SPREAD,l.B.INLINE_FRAGMENT],args:{if:{type:new c.bM(d.EZ),description:"Skipped when true."}}}),v="No longer supported",y=new h({name:"deprecated",description:"Marks an element of a GraphQL schema as no longer supported.",locations:[l.B.FIELD_DEFINITION,l.B.ARGUMENT_DEFINITION,l.B.INPUT_FIELD_DEFINITION,l.B.ENUM_VALUE],args:{reason:{type:d.kH,description:"Explains why this element was deprecated, usually also including a suggestion for how to access supported similar data. Formatted using the Markdown syntax, as specified by [CommonMark](https://commonmark.org/).",defaultValue:v}}}),b=new h({name:"specifiedBy",description:"Exposes a URL that specifies the behavior of this scalar.",locations:[l.B.SCALAR],args:{url:{type:new c.bM(d.kH),description:"The URL that specifies the behavior of this scalar."}}}),E=Object.freeze([m,g,y,b]);function T(e){return E.some((({name:t})=>t===e.name))}},8078:function(e,t,n){"use strict";n.d(t,{Az:function(){return b},PX:function(){return y},TK:function(){return c},XQ:function(){return m},e_:function(){return h},hU:function(){return T},jT:function(){return g},l3:function(){return d},nL:function(){return w},qz:function(){return p},s9:function(){return C},tF:function(){return E},x2:function(){return f},zU:function(){return v}});var r=n(5648),i=n(5052),o=n(3140),a=n(5895),s=n(3190),l=n(755),u=n(1774);const c=new l.h6({name:"__Schema",description:"A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query, mutation, and subscription operations.",fields:()=>({description:{type:u.kH,resolve:e=>e.description},types:{description:"A list of all types supported by this server.",type:new l.bM(new l.p2(new l.bM(p))),resolve(e){return Object.values(e.getTypeMap())}},queryType:{description:"The type that query operations will be rooted at.",type:new l.bM(p),resolve:e=>e.getQueryType()},mutationType:{description:"If this server supports mutation, the type that mutation operations will be rooted at.",type:p,resolve:e=>e.getMutationType()},subscriptionType:{description:"If this server support subscription, the type that subscription operations will be rooted at.",type:p,resolve:e=>e.getSubscriptionType()},directives:{description:"A list of all directives supported by this server.",type:new l.bM(new l.p2(new l.bM(d))),resolve:e=>e.getDirectives()}})}),d=new l.h6({name:"__Directive",description:"A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.\n\nIn some cases, you need to provide options to alter GraphQL's execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor.",fields:()=>({name:{type:new l.bM(u.kH),resolve:e=>e.name},description:{type:u.kH,resolve:e=>e.description},isRepeatable:{type:new l.bM(u.EZ),resolve:e=>e.isRepeatable},locations:{type:new l.bM(new l.p2(new l.bM(f))),resolve:e=>e.locations},args:{type:new l.bM(new l.p2(new l.bM(m))),args:{includeDeprecated:{type:u.EZ,defaultValue:!1}},resolve(e,{includeDeprecated:t}){return t?e.args:e.args.filter((e=>null==e.deprecationReason))}}})}),f=new l.mR({name:"__DirectiveLocation",description:"A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies.",values:{QUERY:{value:o.B.QUERY,description:"Location adjacent to a query operation."},MUTATION:{value:o.B.MUTATION,description:"Location adjacent to a mutation operation."},SUBSCRIPTION:{value:o.B.SUBSCRIPTION,description:"Location adjacent to a subscription operation."},FIELD:{value:o.B.FIELD,description:"Location adjacent to a field."},FRAGMENT_DEFINITION:{value:o.B.FRAGMENT_DEFINITION,description:"Location adjacent to a fragment definition."},FRAGMENT_SPREAD:{value:o.B.FRAGMENT_SPREAD,description:"Location adjacent to a fragment spread."},INLINE_FRAGMENT:{value:o.B.INLINE_FRAGMENT,description:"Location adjacent to an inline fragment."},VARIABLE_DEFINITION:{value:o.B.VARIABLE_DEFINITION,description:"Location adjacent to a variable definition."},SCHEMA:{value:o.B.SCHEMA,description:"Location adjacent to a schema definition."},SCALAR:{value:o.B.SCALAR,description:"Location adjacent to a scalar definition."},OBJECT:{value:o.B.OBJECT,description:"Location adjacent to an object type definition."},FIELD_DEFINITION:{value:o.B.FIELD_DEFINITION,description:"Location adjacent to a field definition."},ARGUMENT_DEFINITION:{value:o.B.ARGUMENT_DEFINITION,description:"Location adjacent to an argument definition."},INTERFACE:{value:o.B.INTERFACE,description:"Location adjacent to an interface definition."},UNION:{value:o.B.UNION,description:"Location adjacent to a union definition."},ENUM:{value:o.B.ENUM,description:"Location adjacent to an enum definition."},ENUM_VALUE:{value:o.B.ENUM_VALUE,description:"Location adjacent to an enum value definition."},INPUT_OBJECT:{value:o.B.INPUT_OBJECT,description:"Location adjacent to an input object type definition."},INPUT_FIELD_DEFINITION:{value:o.B.INPUT_FIELD_DEFINITION,description:"Location adjacent to an input object field definition."}}}),p=new l.h6({name:"__Type",description:"The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the `__TypeKind` enum.\n\nDepending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name, description and optional `specifiedByURL`, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose other types.",fields:()=>({kind:{type:new l.bM(y),resolve(e){return(0,l.KA)(e)?v.SCALAR:(0,l.lp)(e)?v.OBJECT:(0,l.oT)(e)?v.INTERFACE:(0,l.EN)(e)?v.UNION:(0,l.EM)(e)?v.ENUM:(0,l.hL)(e)?v.INPUT_OBJECT:(0,l.HG)(e)?v.LIST:(0,l.zM)(e)?v.NON_NULL:void(0,i.k)(!1,`Unexpected type: "${(0,r.X)(e)}".`)}},name:{type:u.kH,resolve:e=>"name"in e?e.name:void 0},description:{type:u.kH,resolve:e=>"description"in e?e.description:void 0},specifiedByURL:{type:u.kH,resolve:e=>"specifiedByURL"in e?e.specifiedByURL:void 0},fields:{type:new l.p2(new l.bM(h)),args:{includeDeprecated:{type:u.EZ,defaultValue:!1}},resolve(e,{includeDeprecated:t}){if((0,l.lp)(e)||(0,l.oT)(e)){const n=Object.values(e.getFields());return t?n:n.filter((e=>null==e.deprecationReason))}}},interfaces:{type:new l.p2(new l.bM(p)),resolve(e){if((0,l.lp)(e)||(0,l.oT)(e))return e.getInterfaces()}},possibleTypes:{type:new l.p2(new l.bM(p)),resolve(e,t,n,{schema:r}){if((0,l.m0)(e))return r.getPossibleTypes(e)}},enumValues:{type:new l.p2(new l.bM(g)),args:{includeDeprecated:{type:u.EZ,defaultValue:!1}},resolve(e,{includeDeprecated:t}){if((0,l.EM)(e)){const n=e.getValues();return t?n:n.filter((e=>null==e.deprecationReason))}}},inputFields:{type:new l.p2(new l.bM(m)),args:{includeDeprecated:{type:u.EZ,defaultValue:!1}},resolve(e,{includeDeprecated:t}){if((0,l.hL)(e)){const n=Object.values(e.getFields());return t?n:n.filter((e=>null==e.deprecationReason))}}},ofType:{type:p,resolve:e=>"ofType"in e?e.ofType:void 0}})}),h=new l.h6({name:"__Field",description:"Object and Interface types are described by a list of Fields, each of which has a name, potentially a list of arguments, and a return type.",fields:()=>({name:{type:new l.bM(u.kH),resolve:e=>e.name},description:{type:u.kH,resolve:e=>e.description},args:{type:new l.bM(new l.p2(new l.bM(m))),args:{includeDeprecated:{type:u.EZ,defaultValue:!1}},resolve(e,{includeDeprecated:t}){return t?e.args:e.args.filter((e=>null==e.deprecationReason))}},type:{type:new l.bM(p),resolve:e=>e.type},isDeprecated:{type:new l.bM(u.EZ),resolve:e=>null!=e.deprecationReason},deprecationReason:{type:u.kH,resolve:e=>e.deprecationReason}})}),m=new l.h6({name:"__InputValue",description:"Arguments provided to Fields or Directives and the input fields of an InputObject are represented as Input Values which describe their type and optionally a default value.",fields:()=>({name:{type:new l.bM(u.kH),resolve:e=>e.name},description:{type:u.kH,resolve:e=>e.description},type:{type:new l.bM(p),resolve:e=>e.type},defaultValue:{type:u.kH,description:"A GraphQL-formatted string representing the default value for this input value.",resolve(e){const{type:t,defaultValue:n}=e,r=(0,s.J)(n,t);return r?(0,a.S)(r):null}},isDeprecated:{type:new l.bM(u.EZ),resolve:e=>null!=e.deprecationReason},deprecationReason:{type:u.kH,resolve:e=>e.deprecationReason}})}),g=new l.h6({name:"__EnumValue",description:"One possible value for a given Enum. Enum values are unique values, not a placeholder for a string or numeric value. However an Enum value is returned in a JSON response as a string.",fields:()=>({name:{type:new l.bM(u.kH),resolve:e=>e.name},description:{type:u.kH,resolve:e=>e.description},isDeprecated:{type:new l.bM(u.EZ),resolve:e=>null!=e.deprecationReason},deprecationReason:{type:u.kH,resolve:e=>e.deprecationReason}})});let v;!function(e){e.SCALAR="SCALAR",e.OBJECT="OBJECT",e.INTERFACE="INTERFACE",e.UNION="UNION",e.ENUM="ENUM",e.INPUT_OBJECT="INPUT_OBJECT",e.LIST="LIST",e.NON_NULL="NON_NULL"}(v||(v={}));const y=new l.mR({name:"__TypeKind",description:"An enum describing what kind of type a given `__Type` is.",values:{SCALAR:{value:v.SCALAR,description:"Indicates this type is a scalar."},OBJECT:{value:v.OBJECT,description:"Indicates this type is an object. `fields` and `interfaces` are valid fields."},INTERFACE:{value:v.INTERFACE,description:"Indicates this type is an interface. `fields`, `interfaces`, and `possibleTypes` are valid fields."},UNION:{value:v.UNION,description:"Indicates this type is a union. `possibleTypes` is a valid field."},ENUM:{value:v.ENUM,description:"Indicates this type is an enum. `enumValues` is a valid field."},INPUT_OBJECT:{value:v.INPUT_OBJECT,description:"Indicates this type is an input object. `inputFields` is a valid field."},LIST:{value:v.LIST,description:"Indicates this type is a list. `ofType` is a valid field."},NON_NULL:{value:v.NON_NULL,description:"Indicates this type is a non-null. `ofType` is a valid field."}}}),b={name:"__schema",type:new l.bM(c),description:"Access the current type schema of this server.",args:[],resolve:(e,t,n,{schema:r})=>r,deprecationReason:void 0,extensions:Object.create(null),astNode:void 0},E={name:"__type",type:p,description:"Request the type information of a single type.",args:[{name:"name",description:void 0,type:new l.bM(u.kH),defaultValue:void 0,deprecationReason:void 0,extensions:Object.create(null),astNode:void 0}],resolve:(e,{name:t},n,{schema:r})=>r.getType(t),deprecationReason:void 0,extensions:Object.create(null),astNode:void 0},T={name:"__typename",type:new l.bM(u.kH),description:"The name of the current Object type at runtime.",args:[],resolve:(e,t,n,{parentType:r})=>r.name,deprecationReason:void 0,extensions:Object.create(null),astNode:void 0},w=Object.freeze([c,d,f,p,h,m,g,y]);function C(e){return w.some((({name:t})=>e.name===t))}},1774:function(e,t,n){"use strict";n.d(t,{EZ:function(){return h},HI:function(){return u},HS:function(){return g},_o:function(){return d},av:function(){return f},kH:function(){return p},km:function(){return m},st:function(){return c},u1:function(){return v}});var r=n(5648),i=n(1315),o=n(4117),a=n(3830),s=n(5895),l=n(755);const u=2147483647,c=-2147483648,d=new l.n2({name:"Int",description:"The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.",serialize(e){const t=y(e);if("boolean"==typeof t)return t?1:0;let n=t;if("string"==typeof t&&""!==t&&(n=Number(t)),"number"!=typeof n||!Number.isInteger(n))throw new o.__(`Int cannot represent non-integer value: ${(0,r.X)(t)}`);if(n>u||nu||eu||te.name===t))}function y(e){if((0,i.y)(e)){if("function"==typeof e.valueOf){const t=e.valueOf();if(!(0,i.y)(t))return t}if("function"==typeof e.toJSON)return e.toJSON()}return e}},773:function(e,t,n){"use strict";n.d(t,{EO:function(){return p},XO:function(){return h},nN:function(){return f}});var r=n(1172),i=n(5648),o=n(1513),a=n(1315),s=n(1140),l=n(3526),u=n(755),c=n(5946),d=n(8078);function f(e){return(0,o.n)(e,h)}function p(e){if(!f(e))throw new Error(`Expected ${(0,i.X)(e)} to be a GraphQL schema.`);return e}class h{constructor(e){var t,n;this.__validationErrors=!0===e.assumeValid?[]:void 0,(0,a.y)(e)||(0,r.a)(!1,"Must provide configuration object."),!e.types||Array.isArray(e.types)||(0,r.a)(!1,`"types" must be Array if provided but got: ${(0,i.X)(e.types)}.`),!e.directives||Array.isArray(e.directives)||(0,r.a)(!1,`"directives" must be Array if provided but got: ${(0,i.X)(e.directives)}.`),this.description=e.description,this.extensions=(0,s.u)(e.extensions),this.astNode=e.astNode,this.extensionASTNodes=null!==(t=e.extensionASTNodes)&&void 0!==t?t:[],this._queryType=e.query,this._mutationType=e.mutation,this._subscriptionType=e.subscription,this._directives=null!==(n=e.directives)&&void 0!==n?n:c.V4;const o=new Set(e.types);if(null!=e.types)for(const t of e.types)o.delete(t),m(t,o);null!=this._queryType&&m(this._queryType,o),null!=this._mutationType&&m(this._mutationType,o),null!=this._subscriptionType&&m(this._subscriptionType,o);for(const e of this._directives)if((0,c.wX)(e))for(const t of e.args)m(t.type,o);m(d.TK,o),this._typeMap=Object.create(null),this._subTypeMap=Object.create(null),this._implementationsMap=Object.create(null);for(const e of o){if(null==e)continue;const t=e.name;if(t||(0,r.a)(!1,"One of the provided types for building the Schema is missing a name."),void 0!==this._typeMap[t])throw new Error(`Schema must contain uniquely named types but contains multiple types named "${t}".`);if(this._typeMap[t]=e,(0,u.oT)(e)){for(const t of e.getInterfaces())if((0,u.oT)(t)){let n=this._implementationsMap[t.name];void 0===n&&(n=this._implementationsMap[t.name]={objects:[],interfaces:[]}),n.interfaces.push(e)}}else if((0,u.lp)(e))for(const t of e.getInterfaces())if((0,u.oT)(t)){let n=this._implementationsMap[t.name];void 0===n&&(n=this._implementationsMap[t.name]={objects:[],interfaces:[]}),n.objects.push(e)}}}get[Symbol.toStringTag](){return"GraphQLSchema"}getQueryType(){return this._queryType}getMutationType(){return this._mutationType}getSubscriptionType(){return this._subscriptionType}getRootType(e){switch(e){case l.ku.QUERY:return this.getQueryType();case l.ku.MUTATION:return this.getMutationType();case l.ku.SUBSCRIPTION:return this.getSubscriptionType()}}getTypeMap(){return this._typeMap}getType(e){return this.getTypeMap()[e]}getPossibleTypes(e){return(0,u.EN)(e)?e.getTypes():this.getImplementations(e).objects}getImplementations(e){const t=this._implementationsMap[e.name];return null!=t?t:{objects:[],interfaces:[]}}isSubType(e,t){let n=this._subTypeMap[e.name];if(void 0===n){if(n=Object.create(null),(0,u.EN)(e))for(const t of e.getTypes())n[t.name]=!0;else{const t=this.getImplementations(e);for(const e of t.objects)n[e.name]=!0;for(const e of t.interfaces)n[e.name]=!0}this._subTypeMap[e.name]=n}return void 0!==n[t.name]}getDirectives(){return this._directives}getDirective(e){return this.getDirectives().find((t=>t.name===e))}toConfig(){return{description:this.description,query:this.getQueryType(),mutation:this.getMutationType(),subscription:this.getSubscriptionType(),types:Object.values(this.getTypeMap()),directives:this.getDirectives(),extensions:this.extensions,astNode:this.astNode,extensionASTNodes:this.extensionASTNodes,assumeValid:void 0!==this.__validationErrors}}}function m(e,t){const n=(0,u.xC)(e);if(!t.has(n))if(t.add(n),(0,u.EN)(n))for(const e of n.getTypes())m(e,t);else if((0,u.lp)(n)||(0,u.oT)(n)){for(const e of n.getInterfaces())m(e,t);for(const e of Object.values(n.getFields())){m(e.type,t);for(const n of e.args)m(n.type,t)}}else if((0,u.hL)(n))for(const e of Object.values(n.getFields()))m(e.type,t);return t}},8555:function(e,t,n){"use strict";n.d(t,{F:function(){return d},J:function(){return f}});var r=n(5648),i=n(4117),o=n(3526),a=n(2984),s=n(755),l=n(5946),u=n(8078),c=n(773);function d(e){if((0,c.EO)(e),e.__validationErrors)return e.__validationErrors;const t=new p(e);!function(e){const t=e.schema,n=t.getQueryType();if(n){if(!(0,s.lp)(n)){var i;e.reportError(`Query root type must be Object type, it cannot be ${(0,r.X)(n)}.`,null!==(i=h(t,o.ku.QUERY))&&void 0!==i?i:n.astNode)}}else e.reportError("Query root type must be provided.",t.astNode);const a=t.getMutationType();var l;a&&!(0,s.lp)(a)&&e.reportError(`Mutation root type must be Object type if provided, it cannot be ${(0,r.X)(a)}.`,null!==(l=h(t,o.ku.MUTATION))&&void 0!==l?l:a.astNode);const u=t.getSubscriptionType();var c;u&&!(0,s.lp)(u)&&e.reportError(`Subscription root type must be Object type if provided, it cannot be ${(0,r.X)(u)}.`,null!==(c=h(t,o.ku.SUBSCRIPTION))&&void 0!==c?c:u.astNode)}(t),function(e){for(const n of e.schema.getDirectives())if((0,l.wX)(n)){m(e,n);for(const i of n.args){var t;m(e,i),(0,s.j$)(i.type)||e.reportError(`The type of @${n.name}(${i.name}:) must be Input Type but got: ${(0,r.X)(i.type)}.`,i.astNode),(0,s.dK)(i)&&null!=i.deprecationReason&&e.reportError(`Required argument @${n.name}(${i.name}:) cannot be deprecated.`,[x(i.astNode),null===(t=i.astNode)||void 0===t?void 0:t.type])}}else e.reportError(`Expected directive but got: ${(0,r.X)(n)}.`,null==n?void 0:n.astNode)}(t),function(e){const t=function(e){const t=Object.create(null),n=[],r=Object.create(null);return function i(o){if(t[o.name])return;t[o.name]=!0,r[o.name]=n.length;const a=Object.values(o.getFields());for(const t of a)if((0,s.zM)(t.type)&&(0,s.hL)(t.type.ofType)){const o=t.type.ofType,a=r[o.name];if(n.push(t),void 0===a)i(o);else{const t=n.slice(a),r=t.map((e=>e.name)).join(".");e.reportError(`Cannot reference Input Object "${o.name}" within itself through a series of non-null fields: "${r}".`,t.map((e=>e.astNode)))}n.pop()}r[o.name]=void 0}}(e),n=e.schema.getTypeMap();for(const i of Object.values(n))(0,s.Zs)(i)?((0,u.s9)(i)||m(e,i),(0,s.lp)(i)||(0,s.oT)(i)?(g(e,i),v(e,i)):(0,s.EN)(i)?E(e,i):(0,s.EM)(i)?T(e,i):(0,s.hL)(i)&&(w(e,i),t(i))):e.reportError(`Expected GraphQL named type but got: ${(0,r.X)(i)}.`,i.astNode)}(t);const n=t.getErrors();return e.__validationErrors=n,n}function f(e){const t=d(e);if(0!==t.length)throw new Error(t.map((e=>e.message)).join("\n\n"))}class p{constructor(e){this._errors=[],this.schema=e}reportError(e,t){const n=Array.isArray(t)?t.filter(Boolean):t;this._errors.push(new i.__(e,{nodes:n}))}getErrors(){return this._errors}}function h(e,t){var n;return null===(n=[e.astNode,...e.extensionASTNodes].flatMap((e=>{var t;return null!==(t=null==e?void 0:e.operationTypes)&&void 0!==t?t:[]})).find((e=>e.operation===t)))||void 0===n?void 0:n.type}function m(e,t){t.name.startsWith("__")&&e.reportError(`Name "${t.name}" must not begin with "__", which is reserved by GraphQL introspection.`,t.astNode)}function g(e,t){const n=Object.values(t.getFields());0===n.length&&e.reportError(`Type ${t.name} must define one or more fields.`,[t.astNode,...t.extensionASTNodes]);for(const l of n){var i;m(e,l),(0,s.SZ)(l.type)||e.reportError(`The type of ${t.name}.${l.name} must be Output Type but got: ${(0,r.X)(l.type)}.`,null===(i=l.astNode)||void 0===i?void 0:i.type);for(const n of l.args){const i=n.name;var o,a;m(e,n),(0,s.j$)(n.type)||e.reportError(`The type of ${t.name}.${l.name}(${i}:) must be Input Type but got: ${(0,r.X)(n.type)}.`,null===(o=n.astNode)||void 0===o?void 0:o.type),(0,s.dK)(n)&&null!=n.deprecationReason&&e.reportError(`Required argument ${t.name}.${l.name}(${i}:) cannot be deprecated.`,[x(n.astNode),null===(a=n.astNode)||void 0===a?void 0:a.type])}}}function v(e,t){const n=Object.create(null);for(const i of t.getInterfaces())(0,s.oT)(i)?t!==i?n[i.name]?e.reportError(`Type ${t.name} can only implement ${i.name} once.`,C(t,i)):(n[i.name]=!0,b(e,t,i),y(e,t,i)):e.reportError(`Type ${t.name} cannot implement itself because it would create a circular reference.`,C(t,i)):e.reportError(`Type ${(0,r.X)(t)} must only implement Interface types, it cannot implement ${(0,r.X)(i)}.`,C(t,i))}function y(e,t,n){const i=t.getFields();for(const d of Object.values(n.getFields())){const f=d.name,p=i[f];if(p){var o,l;(0,a.uJ)(e.schema,p.type,d.type)||e.reportError(`Interface field ${n.name}.${f} expects type ${(0,r.X)(d.type)} but ${t.name}.${f} is type ${(0,r.X)(p.type)}.`,[null===(o=d.astNode)||void 0===o?void 0:o.type,null===(l=p.astNode)||void 0===l?void 0:l.type]);for(const i of d.args){const o=i.name,s=p.args.find((e=>e.name===o));var u,c;s?(0,a._7)(i.type,s.type)||e.reportError(`Interface field argument ${n.name}.${f}(${o}:) expects type ${(0,r.X)(i.type)} but ${t.name}.${f}(${o}:) is type ${(0,r.X)(s.type)}.`,[null===(u=i.astNode)||void 0===u?void 0:u.type,null===(c=s.astNode)||void 0===c?void 0:c.type]):e.reportError(`Interface field argument ${n.name}.${f}(${o}:) expected but ${t.name}.${f} does not provide it.`,[i.astNode,p.astNode])}for(const r of p.args){const i=r.name;!d.args.find((e=>e.name===i))&&(0,s.dK)(r)&&e.reportError(`Object field ${t.name}.${f} includes required argument ${i} that is missing from the Interface field ${n.name}.${f}.`,[r.astNode,d.astNode])}}else e.reportError(`Interface field ${n.name}.${f} expected but ${t.name} does not provide it.`,[d.astNode,t.astNode,...t.extensionASTNodes])}}function b(e,t,n){const r=t.getInterfaces();for(const i of n.getInterfaces())r.includes(i)||e.reportError(i===t?`Type ${t.name} cannot implement ${n.name} because it would create a circular reference.`:`Type ${t.name} must implement ${i.name} because it is implemented by ${n.name}.`,[...C(n,i),...C(t,n)])}function E(e,t){const n=t.getTypes();0===n.length&&e.reportError(`Union type ${t.name} must define one or more member types.`,[t.astNode,...t.extensionASTNodes]);const i=Object.create(null);for(const o of n)i[o.name]?e.reportError(`Union type ${t.name} can only include type ${o.name} once.`,S(t,o.name)):(i[o.name]=!0,(0,s.lp)(o)||e.reportError(`Union type ${t.name} can only include Object types, it cannot include ${(0,r.X)(o)}.`,S(t,String(o))))}function T(e,t){const n=t.getValues();0===n.length&&e.reportError(`Enum type ${t.name} must define one or more values.`,[t.astNode,...t.extensionASTNodes]);for(const t of n)m(e,t)}function w(e,t){const n=Object.values(t.getFields());0===n.length&&e.reportError(`Input Object type ${t.name} must define one or more fields.`,[t.astNode,...t.extensionASTNodes]);for(const a of n){var i,o;m(e,a),(0,s.j$)(a.type)||e.reportError(`The type of ${t.name}.${a.name} must be Input Type but got: ${(0,r.X)(a.type)}.`,null===(i=a.astNode)||void 0===i?void 0:i.type),(0,s.Wd)(a)&&null!=a.deprecationReason&&e.reportError(`Required input field ${t.name}.${a.name} cannot be deprecated.`,[x(a.astNode),null===(o=a.astNode)||void 0===o?void 0:o.type])}}function C(e,t){const{astNode:n,extensionASTNodes:r}=e;return(null!=n?[n,...r]:r).flatMap((e=>{var t;return null!==(t=e.interfaces)&&void 0!==t?t:[]})).filter((e=>e.name.value===t.name))}function S(e,t){const{astNode:n,extensionASTNodes:r}=e;return(null!=n?[n,...r]:r).flatMap((e=>{var t;return null!==(t=e.types)&&void 0!==t?t:[]})).filter((e=>e.name.value===t))}function x(e){var t;return null==e||null===(t=e.directives)||void 0===t?void 0:t.find((e=>e.name.value===l.fg.name))}},1409:function(e,t,n){"use strict";n.d(t,{a:function(){return u},y:function(){return d}});var r=n(3526),i=n(3830),o=n(9685),a=n(755),s=n(8078),l=n(5998);class u{constructor(e,t,n){this._schema=e,this._typeStack=[],this._parentTypeStack=[],this._inputTypeStack=[],this._fieldDefStack=[],this._defaultValueStack=[],this._directive=null,this._argument=null,this._enumValue=null,this._getFieldDef=null!=n?n:c,t&&((0,a.j$)(t)&&this._inputTypeStack.push(t),(0,a.Gv)(t)&&this._parentTypeStack.push(t),(0,a.SZ)(t)&&this._typeStack.push(t))}get[Symbol.toStringTag](){return"TypeInfo"}getType(){if(this._typeStack.length>0)return this._typeStack[this._typeStack.length-1]}getParentType(){if(this._parentTypeStack.length>0)return this._parentTypeStack[this._parentTypeStack.length-1]}getInputType(){if(this._inputTypeStack.length>0)return this._inputTypeStack[this._inputTypeStack.length-1]}getParentInputType(){if(this._inputTypeStack.length>1)return this._inputTypeStack[this._inputTypeStack.length-2]}getFieldDef(){if(this._fieldDefStack.length>0)return this._fieldDefStack[this._fieldDefStack.length-1]}getDefaultValue(){if(this._defaultValueStack.length>0)return this._defaultValueStack[this._defaultValueStack.length-1]}getDirective(){return this._directive}getArgument(){return this._argument}getEnumValue(){return this._enumValue}enter(e){const t=this._schema;switch(e.kind){case i.h.SELECTION_SET:{const e=(0,a.xC)(this.getType());this._parentTypeStack.push((0,a.Gv)(e)?e:void 0);break}case i.h.FIELD:{const n=this.getParentType();let r,i;n&&(r=this._getFieldDef(t,n,e),r&&(i=r.type)),this._fieldDefStack.push(r),this._typeStack.push((0,a.SZ)(i)?i:void 0);break}case i.h.DIRECTIVE:this._directive=t.getDirective(e.name.value);break;case i.h.OPERATION_DEFINITION:{const n=t.getRootType(e.operation);this._typeStack.push((0,a.lp)(n)?n:void 0);break}case i.h.INLINE_FRAGMENT:case i.h.FRAGMENT_DEFINITION:{const n=e.typeCondition,r=n?(0,l._)(t,n):(0,a.xC)(this.getType());this._typeStack.push((0,a.SZ)(r)?r:void 0);break}case i.h.VARIABLE_DEFINITION:{const n=(0,l._)(t,e.type);this._inputTypeStack.push((0,a.j$)(n)?n:void 0);break}case i.h.ARGUMENT:{var n;let t,r;const i=null!==(n=this.getDirective())&&void 0!==n?n:this.getFieldDef();i&&(t=i.args.find((t=>t.name===e.name.value)),t&&(r=t.type)),this._argument=t,this._defaultValueStack.push(t?t.defaultValue:void 0),this._inputTypeStack.push((0,a.j$)(r)?r:void 0);break}case i.h.LIST:{const e=(0,a.tf)(this.getInputType()),t=(0,a.HG)(e)?e.ofType:e;this._defaultValueStack.push(void 0),this._inputTypeStack.push((0,a.j$)(t)?t:void 0);break}case i.h.OBJECT_FIELD:{const t=(0,a.xC)(this.getInputType());let n,r;(0,a.hL)(t)&&(r=t.getFields()[e.name.value],r&&(n=r.type)),this._defaultValueStack.push(r?r.defaultValue:void 0),this._inputTypeStack.push((0,a.j$)(n)?n:void 0);break}case i.h.ENUM:{const t=(0,a.xC)(this.getInputType());let n;(0,a.EM)(t)&&(n=t.getValue(e.value)),this._enumValue=n;break}}}leave(e){switch(e.kind){case i.h.SELECTION_SET:this._parentTypeStack.pop();break;case i.h.FIELD:this._fieldDefStack.pop(),this._typeStack.pop();break;case i.h.DIRECTIVE:this._directive=null;break;case i.h.OPERATION_DEFINITION:case i.h.INLINE_FRAGMENT:case i.h.FRAGMENT_DEFINITION:this._typeStack.pop();break;case i.h.VARIABLE_DEFINITION:this._inputTypeStack.pop();break;case i.h.ARGUMENT:this._argument=null,this._defaultValueStack.pop(),this._inputTypeStack.pop();break;case i.h.LIST:case i.h.OBJECT_FIELD:this._defaultValueStack.pop(),this._inputTypeStack.pop();break;case i.h.ENUM:this._enumValue=null}}}function c(e,t,n){const r=n.name.value;return r===s.Az.name&&e.getQueryType()===t?s.Az:r===s.tF.name&&e.getQueryType()===t?s.tF:r===s.hU.name&&(0,a.Gv)(t)?s.hU:(0,a.lp)(t)||(0,a.oT)(t)?t.getFields()[r]:void 0}function d(e,t){return{enter(...n){const i=n[0];e.enter(i);const a=(0,o.Eu)(t,i.kind).enter;if(a){const o=a.apply(t,n);return void 0!==o&&(e.leave(i),(0,r.UG)(o)&&e.enter(o)),o}},leave(...n){const r=n[0],i=(0,o.Eu)(t,r.kind).leave;let a;return i&&(a=i.apply(t,n)),e.leave(r),a}}}},3190:function(e,t,n){"use strict";n.d(t,{J:function(){return c}});var r=n(5648),i=n(5052),o=n(2910),a=n(1315),s=n(3830),l=n(755),u=n(1774);function c(e,t){if((0,l.zM)(t)){const n=c(e,t.ofType);return(null==n?void 0:n.kind)===s.h.NULL?null:n}if(null===e)return{kind:s.h.NULL};if(void 0===e)return null;if((0,l.HG)(t)){const n=t.ofType;if((0,o.i)(e)){const t=[];for(const r of e){const e=c(r,n);null!=e&&t.push(e)}return{kind:s.h.LIST,values:t}}return c(e,n)}if((0,l.hL)(t)){if(!(0,a.y)(e))return null;const n=[];for(const r of Object.values(t.getFields())){const t=c(e[r.name],r.type);t&&n.push({kind:s.h.OBJECT_FIELD,name:{kind:s.h.NAME,value:r.name},value:t})}return{kind:s.h.OBJECT,fields:n}}if((0,l.UT)(t)){const n=t.serialize(e);if(null==n)return null;if("boolean"==typeof n)return{kind:s.h.BOOLEAN,value:n};if("number"==typeof n&&Number.isFinite(n)){const e=String(n);return d.test(e)?{kind:s.h.INT,value:e}:{kind:s.h.FLOAT,value:e}}if("string"==typeof n)return(0,l.EM)(t)?{kind:s.h.ENUM,value:n}:t===u.km&&d.test(n)?{kind:s.h.INT,value:n}:{kind:s.h.STRING,value:n};throw new TypeError(`Cannot convert value to AST: ${(0,r.X)(n)}.`)}(0,i.k)(!1,"Unexpected input type: "+(0,r.X)(t))}const d=/^-?(?:0|[1-9][0-9]*)$/},5925:function(e,t,n){"use strict";n.d(t,{K:function(){return p}});var r=n(8063),i=n(5648),o=n(5052),a=n(2910),s=n(1315),l=n(9878),u=n(4987),c=n(3492),d=n(4117),f=n(755);function p(e,t,n=h){return m(e,t,n,void 0)}function h(e,t,n){let r="Invalid value "+(0,i.X)(t);throw e.length>0&&(r+=` at "value${(0,u.F)(e)}"`),n.message=r+": "+n.message,n}function m(e,t,n,u){if((0,f.zM)(t))return null!=e?m(e,t.ofType,n,u):void n((0,l.N)(u),e,new d.__(`Expected non-nullable type "${(0,i.X)(t)}" not to be null.`));if(null==e)return null;if((0,f.HG)(t)){const r=t.ofType;return(0,a.i)(e)?Array.from(e,((e,t)=>{const i=(0,l.Q)(u,t,void 0);return m(e,r,n,i)})):[m(e,r,n,u)]}if((0,f.hL)(t)){if(!(0,s.y)(e))return void n((0,l.N)(u),e,new d.__(`Expected type "${t.name}" to be an object.`));const o={},a=t.getFields();for(const r of Object.values(a)){const a=e[r.name];if(void 0!==a)o[r.name]=m(a,r.type,n,(0,l.Q)(u,r.name,t.name));else if(void 0!==r.defaultValue)o[r.name]=r.defaultValue;else if((0,f.zM)(r.type)){const t=(0,i.X)(r.type);n((0,l.N)(u),e,new d.__(`Field "${r.name}" of required type "${t}" was not provided.`))}}for(const i of Object.keys(e))if(!a[i]){const o=(0,c.D)(i,Object.keys(t.getFields()));n((0,l.N)(u),e,new d.__(`Field "${i}" is not defined by type "${t.name}".`+(0,r.l)(o)))}return o}if((0,f.UT)(t)){let r;try{r=t.parseValue(e)}catch(r){return void(r instanceof d.__?n((0,l.N)(u),e,r):n((0,l.N)(u),e,new d.__(`Expected type "${t.name}". `+r.message,{originalError:r})))}return void 0===r&&n((0,l.N)(u),e,new d.__(`Expected type "${t.name}".`)),r}(0,o.k)(!1,"Unexpected input type: "+(0,i.X)(t))}},9458:function(e,t,n){"use strict";n.d(t,{S:function(){return i}});var r=n(3830);function i(e,t){let n=null;for(const o of e.definitions){var i;if(o.kind===r.h.OPERATION_DEFINITION)if(null==t){if(n)return null;n=o}else if((null===(i=o.name)||void 0===i?void 0:i.value)===t)return o}return n}},4034:function(e,t,n){"use strict";n.d(t,{n:function(){return o}});var r=n(6625),i=n(3830);function o(e){switch(e.kind){case i.h.OBJECT:return{...e,fields:(t=e.fields,t.map((e=>({...e,value:o(e.value)}))).sort(((e,t)=>(0,r.K)(e.name.value,t.name.value))))};case i.h.LIST:return{...e,values:e.values.map(o)};case i.h.INT:case i.h.FLOAT:case i.h.STRING:case i.h.BOOLEAN:case i.h.NULL:case i.h.ENUM:case i.h.VARIABLE:return e}var t}},2984:function(e,t,n){"use strict";n.d(t,{_7:function(){return i},uJ:function(){return o},zR:function(){return a}});var r=n(755);function i(e,t){return e===t||((0,r.zM)(e)&&(0,r.zM)(t)||!(!(0,r.HG)(e)||!(0,r.HG)(t)))&&i(e.ofType,t.ofType)}function o(e,t,n){return t===n||((0,r.zM)(n)?!!(0,r.zM)(t)&&o(e,t.ofType,n.ofType):(0,r.zM)(t)?o(e,t.ofType,n):(0,r.HG)(n)?!!(0,r.HG)(t)&&o(e,t.ofType,n.ofType):!(0,r.HG)(t)&&(0,r.m0)(n)&&((0,r.oT)(t)||(0,r.lp)(t))&&e.isSubType(n,t))}function a(e,t,n){return t===n||((0,r.m0)(t)?(0,r.m0)(n)?e.getPossibleTypes(t).some((t=>e.isSubType(n,t))):e.isSubType(t,n):!!(0,r.m0)(n)&&e.isSubType(n,t))}},5998:function(e,t,n){"use strict";n.d(t,{_:function(){return o}});var r=n(3830),i=n(755);function o(e,t){switch(t.kind){case r.h.LIST_TYPE:{const n=o(e,t.type);return n&&new i.p2(n)}case r.h.NON_NULL_TYPE:{const n=o(e,t.type);return n&&new i.bM(n)}case r.h.NAMED_TYPE:return e.getType(t.name.value)}}},5284:function(e,t,n){"use strict";n.d(t,{u:function(){return l}});var r=n(5648),i=n(5052),o=n(9815),a=n(3830),s=n(755);function l(e,t,n){if(e){if(e.kind===a.h.VARIABLE){const r=e.name.value;if(null==n||void 0===n[r])return;const i=n[r];if(null===i&&(0,s.zM)(t))return;return i}if((0,s.zM)(t)){if(e.kind===a.h.NULL)return;return l(e,t.ofType,n)}if(e.kind===a.h.NULL)return null;if((0,s.HG)(t)){const r=t.ofType;if(e.kind===a.h.LIST){const t=[];for(const i of e.values)if(u(i,n)){if((0,s.zM)(r))return;t.push(null)}else{const e=l(i,r,n);if(void 0===e)return;t.push(e)}return t}const i=l(e,r,n);if(void 0===i)return;return[i]}if((0,s.hL)(t)){if(e.kind!==a.h.OBJECT)return;const r=Object.create(null),i=(0,o.P)(e.fields,(e=>e.name.value));for(const e of Object.values(t.getFields())){const t=i[e.name];if(!t||u(t.value,n)){if(void 0!==e.defaultValue)r[e.name]=e.defaultValue;else if((0,s.zM)(e.type))return;continue}const o=l(t.value,e.type,n);if(void 0===o)return;r[e.name]=o}return r}if((0,s.UT)(t)){let r;try{r=t.parseLiteral(e,n)}catch(e){return}if(void 0===r)return;return r}(0,i.k)(!1,"Unexpected input type: "+(0,r.X)(t))}}function u(e,t){return e.kind===a.h.VARIABLE&&(null==t||void 0===t[e.name.value])}},9426:function(e,t,n){"use strict";n.d(t,{M:function(){return o}});var r=n(8240),i=n(3830);function o(e,t){switch(e.kind){case i.h.NULL:return null;case i.h.INT:return parseInt(e.value,10);case i.h.FLOAT:return parseFloat(e.value);case i.h.STRING:case i.h.ENUM:case i.h.BOOLEAN:return e.value;case i.h.LIST:return e.values.map((e=>o(e,t)));case i.h.OBJECT:return(0,r.w)(e.fields,(e=>e.name.value),(e=>o(e.value,t)));case i.h.VARIABLE:return null==t?void 0:t[e.name.value]}}},2716:function(e,t,n){"use strict";n.d(t,{_t:function(){return l},yv:function(){return s}});var r=n(3830),i=n(9685),o=n(1409);class a{constructor(e,t){this._ast=e,this._fragments=void 0,this._fragmentSpreads=new Map,this._recursivelyReferencedFragments=new Map,this._onError=t}get[Symbol.toStringTag](){return"ASTValidationContext"}reportError(e){this._onError(e)}getDocument(){return this._ast}getFragment(e){let t;if(this._fragments)t=this._fragments;else{t=Object.create(null);for(const e of this.getDocument().definitions)e.kind===r.h.FRAGMENT_DEFINITION&&(t[e.name.value]=e);this._fragments=t}return t[e]}getFragmentSpreads(e){let t=this._fragmentSpreads.get(e);if(!t){t=[];const n=[e];let i;for(;i=n.pop();)for(const e of i.selections)e.kind===r.h.FRAGMENT_SPREAD?t.push(e):e.selectionSet&&n.push(e.selectionSet);this._fragmentSpreads.set(e,t)}return t}getRecursivelyReferencedFragments(e){let t=this._recursivelyReferencedFragments.get(e);if(!t){t=[];const n=Object.create(null),r=[e.selectionSet];let i;for(;i=r.pop();)for(const e of this.getFragmentSpreads(i)){const i=e.name.value;if(!0!==n[i]){n[i]=!0;const e=this.getFragment(i);e&&(t.push(e),r.push(e.selectionSet))}}this._recursivelyReferencedFragments.set(e,t)}return t}}class s extends a{constructor(e,t,n){super(e,n),this._schema=t}get[Symbol.toStringTag](){return"SDLValidationContext"}getSchema(){return this._schema}}class l extends a{constructor(e,t,n,r){super(t,r),this._schema=e,this._typeInfo=n,this._variableUsages=new Map,this._recursiveVariableUsages=new Map}get[Symbol.toStringTag](){return"ValidationContext"}getSchema(){return this._schema}getVariableUsages(e){let t=this._variableUsages.get(e);if(!t){const n=[],r=new o.a(this._schema);(0,i.Vn)(e,(0,o.y)(r,{VariableDefinition:()=>!1,Variable(e){n.push({node:e,type:r.getInputType(),defaultValue:r.getDefaultValue()})}})),t=n,this._variableUsages.set(e,t)}return t}getRecursiveVariableUsages(e){let t=this._recursiveVariableUsages.get(e);if(!t){t=this.getVariableUsages(e);for(const n of this.getRecursivelyReferencedFragments(e))t=t.concat(this.getVariableUsages(n));this._recursiveVariableUsages.set(e,t)}return t}getType(){return this._typeInfo.getType()}getParentType(){return this._typeInfo.getParentType()}getInputType(){return this._typeInfo.getInputType()}getParentInputType(){return this._typeInfo.getParentInputType()}getFieldDef(){return this._typeInfo.getFieldDef()}getDirective(){return this._typeInfo.getDirective()}getArgument(){return this._typeInfo.getArgument()}getEnumValue(){return this._typeInfo.getEnumValue()}}},3857:function(e,t,n){"use strict";n.d(t,{i:function(){return a}});var r=n(4117),i=n(3830),o=n(9615);function a(e){return{Document(t){for(const n of t.definitions)if(!(0,o.Wk)(n)){const t=n.kind===i.h.SCHEMA_DEFINITION||n.kind===i.h.SCHEMA_EXTENSION?"schema":'"'+n.name.value+'"';e.reportError(new r.__(`The ${t} definition is not executable.`,{nodes:n}))}return!1}}}},1870:function(e,t,n){"use strict";n.d(t,{A:function(){return l}});var r=n(8063),i=n(6625),o=n(3492),a=n(4117),s=n(755);function l(e){return{Field(t){const n=e.getParentType();if(n&&!e.getFieldDef()){const l=e.getSchema(),u=t.name.value;let c=(0,r.l)("to use an inline fragment on",function(e,t,n){if(!(0,s.m0)(t))return[];const r=new Set,o=Object.create(null);for(const i of e.getPossibleTypes(t))if(i.getFields()[n]){r.add(i),o[i.name]=1;for(const e of i.getInterfaces()){var a;e.getFields()[n]&&(r.add(e),o[e.name]=(null!==(a=o[e.name])&&void 0!==a?a:0)+1)}}return[...r].sort(((t,n)=>{const r=o[n.name]-o[t.name];return 0!==r?r:(0,s.oT)(t)&&e.isSubType(t,n)?-1:(0,s.oT)(n)&&e.isSubType(n,t)?1:(0,i.K)(t.name,n.name)})).map((e=>e.name))}(l,n,u));""===c&&(c=(0,r.l)(function(e,t){if((0,s.lp)(e)||(0,s.oT)(e)){const n=Object.keys(e.getFields());return(0,o.D)(t,n)}return[]}(n,u))),e.reportError(new a.__(`Cannot query field "${u}" on type "${n.name}".`+c,{nodes:t}))}}}}},5167:function(e,t,n){"use strict";n.d(t,{T:function(){return s}});var r=n(4117),i=n(5895),o=n(755),a=n(5998);function s(e){return{InlineFragment(t){const n=t.typeCondition;if(n){const t=(0,a._)(e.getSchema(),n);if(t&&!(0,o.Gv)(t)){const t=(0,i.S)(n);e.reportError(new r.__(`Fragment cannot condition on non composite type "${t}".`,{nodes:n}))}}},FragmentDefinition(t){const n=(0,a._)(e.getSchema(),t.typeCondition);if(n&&!(0,o.Gv)(n)){const n=(0,i.S)(t.typeCondition);e.reportError(new r.__(`Fragment "${t.name.value}" cannot condition on non composite type "${n}".`,{nodes:t.typeCondition}))}}}}},4875:function(e,t,n){"use strict";n.d(t,{e:function(){return l},o:function(){return u}});var r=n(8063),i=n(3492),o=n(4117),a=n(3830),s=n(5946);function l(e){return{...u(e),Argument(t){const n=e.getArgument(),a=e.getFieldDef(),s=e.getParentType();if(!n&&a&&s){const n=t.name.value,l=a.args.map((e=>e.name)),u=(0,i.D)(n,l);e.reportError(new o.__(`Unknown argument "${n}" on field "${s.name}.${a.name}".`+(0,r.l)(u),{nodes:t}))}}}}function u(e){const t=Object.create(null),n=e.getSchema(),l=n?n.getDirectives():s.V4;for(const e of l)t[e.name]=e.args.map((e=>e.name));const u=e.getDocument().definitions;for(const e of u)if(e.kind===a.h.DIRECTIVE_DEFINITION){var c;const n=null!==(c=e.arguments)&&void 0!==c?c:[];t[e.name.value]=n.map((e=>e.name.value))}return{Directive(n){const a=n.name.value,s=t[a];if(n.arguments&&s)for(const t of n.arguments){const n=t.name.value;if(!s.includes(n)){const l=(0,i.D)(n,s);e.reportError(new o.__(`Unknown argument "${n}" on directive "@${a}".`+(0,r.l)(l),{nodes:t}))}}return!1}}}},7513:function(e,t,n){"use strict";n.d(t,{J:function(){return c}});var r=n(5648),i=n(5052),o=n(4117),a=n(3526),s=n(3140),l=n(3830),u=n(5946);function c(e){const t=Object.create(null),n=e.getSchema(),c=n?n.getDirectives():u.V4;for(const e of c)t[e.name]=e.locations;const d=e.getDocument().definitions;for(const e of d)e.kind===l.h.DIRECTIVE_DEFINITION&&(t[e.name.value]=e.locations.map((e=>e.value)));return{Directive(n,u,c,d,f){const p=n.name.value,h=t[p];if(!h)return void e.reportError(new o.__(`Unknown directive "@${p}".`,{nodes:n}));const m=function(e){const t=e[e.length-1];switch("kind"in t||(0,i.k)(!1),t.kind){case l.h.OPERATION_DEFINITION:return function(e){switch(e){case a.ku.QUERY:return s.B.QUERY;case a.ku.MUTATION:return s.B.MUTATION;case a.ku.SUBSCRIPTION:return s.B.SUBSCRIPTION}}(t.operation);case l.h.FIELD:return s.B.FIELD;case l.h.FRAGMENT_SPREAD:return s.B.FRAGMENT_SPREAD;case l.h.INLINE_FRAGMENT:return s.B.INLINE_FRAGMENT;case l.h.FRAGMENT_DEFINITION:return s.B.FRAGMENT_DEFINITION;case l.h.VARIABLE_DEFINITION:return s.B.VARIABLE_DEFINITION;case l.h.SCHEMA_DEFINITION:case l.h.SCHEMA_EXTENSION:return s.B.SCHEMA;case l.h.SCALAR_TYPE_DEFINITION:case l.h.SCALAR_TYPE_EXTENSION:return s.B.SCALAR;case l.h.OBJECT_TYPE_DEFINITION:case l.h.OBJECT_TYPE_EXTENSION:return s.B.OBJECT;case l.h.FIELD_DEFINITION:return s.B.FIELD_DEFINITION;case l.h.INTERFACE_TYPE_DEFINITION:case l.h.INTERFACE_TYPE_EXTENSION:return s.B.INTERFACE;case l.h.UNION_TYPE_DEFINITION:case l.h.UNION_TYPE_EXTENSION:return s.B.UNION;case l.h.ENUM_TYPE_DEFINITION:case l.h.ENUM_TYPE_EXTENSION:return s.B.ENUM;case l.h.ENUM_VALUE_DEFINITION:return s.B.ENUM_VALUE;case l.h.INPUT_OBJECT_TYPE_DEFINITION:case l.h.INPUT_OBJECT_TYPE_EXTENSION:return s.B.INPUT_OBJECT;case l.h.INPUT_VALUE_DEFINITION:{const t=e[e.length-3];return"kind"in t||(0,i.k)(!1),t.kind===l.h.INPUT_OBJECT_TYPE_DEFINITION?s.B.INPUT_FIELD_DEFINITION:s.B.ARGUMENT_DEFINITION}default:(0,i.k)(!1,"Unexpected kind: "+(0,r.X)(t.kind))}}(f);m&&!h.includes(m)&&e.reportError(new o.__(`Directive "@${p}" may not be used on ${m}.`,{nodes:n}))}}}},1435:function(e,t,n){"use strict";n.d(t,{a:function(){return i}});var r=n(4117);function i(e){return{FragmentSpread(t){const n=t.name.value;e.getFragment(n)||e.reportError(new r.__(`Unknown fragment "${n}".`,{nodes:t.name}))}}}},591:function(e,t,n){"use strict";n.d(t,{I:function(){return l}});var r=n(8063),i=n(3492),o=n(4117),a=n(9615),s=n(8078);function l(e){const t=e.getSchema(),n=t?t.getTypeMap():Object.create(null),s=Object.create(null);for(const t of e.getDocument().definitions)(0,a.zT)(t)&&(s[t.name.value]=!0);const l=[...Object.keys(n),...Object.keys(s)];return{NamedType(t,c,d,f,p){const h=t.name.value;if(!n[h]&&!s[h]){var m;const n=null!==(m=p[2])&&void 0!==m?m:d,s=null!=n&&"kind"in(g=n)&&((0,a.G4)(g)||(0,a.aU)(g));if(s&&u.includes(h))return;const c=(0,i.D)(h,s?u.concat(l):l);e.reportError(new o.__(`Unknown type "${h}".`+(0,r.l)(c),{nodes:t}))}var g}}}const u=[...n(1774).HS,...s.nL].map((e=>e.name))},831:function(e,t,n){"use strict";n.d(t,{F:function(){return o}});var r=n(4117),i=n(3830);function o(e){let t=0;return{Document(e){t=e.definitions.filter((e=>e.kind===i.h.OPERATION_DEFINITION)).length},OperationDefinition(n){!n.name&&t>1&&e.reportError(new r.__("This anonymous operation must be the only defined operation.",{nodes:n}))}}}},3402:function(e,t,n){"use strict";n.d(t,{t:function(){return i}});var r=n(4117);function i(e){var t,n,i;const o=e.getSchema(),a=null!==(t=null!==(n=null!==(i=null==o?void 0:o.astNode)&&void 0!==i?i:null==o?void 0:o.getQueryType())&&void 0!==n?n:null==o?void 0:o.getMutationType())&&void 0!==t?t:null==o?void 0:o.getSubscriptionType();let s=0;return{SchemaDefinition(t){a?e.reportError(new r.__("Cannot define a new schema within a schema extension.",{nodes:t})):(s>0&&e.reportError(new r.__("Must provide only one schema definition.",{nodes:t})),++s)}}}},9316:function(e,t,n){"use strict";n.d(t,{H:function(){return i}});var r=n(4117);function i(e){const t=Object.create(null),n=[],i=Object.create(null);return{OperationDefinition:()=>!1,FragmentDefinition(e){return o(e),!1}};function o(a){if(t[a.name.value])return;const s=a.name.value;t[s]=!0;const l=e.getFragmentSpreads(a.selectionSet);if(0!==l.length){i[s]=n.length;for(const t of l){const a=t.name.value,s=i[a];if(n.push(t),void 0===s){const t=e.getFragment(a);t&&o(t)}else{const t=n.slice(s),i=t.slice(0,-1).map((e=>'"'+e.name.value+'"')).join(", ");e.reportError(new r.__(`Cannot spread fragment "${a}" within itself`+(""!==i?` via ${i}.`:"."),{nodes:t}))}n.pop()}i[s]=void 0}}}},9518:function(e,t,n){"use strict";n.d(t,{$:function(){return i}});var r=n(4117);function i(e){let t=Object.create(null);return{OperationDefinition:{enter(){t=Object.create(null)},leave(n){const i=e.getRecursiveVariableUsages(n);for(const{node:o}of i){const i=o.name.value;!0!==t[i]&&e.reportError(new r.__(n.name?`Variable "$${i}" is not defined by operation "${n.name.value}".`:`Variable "$${i}" is not defined.`,{nodes:[o,n]}))}}},VariableDefinition(e){t[e.variable.name.value]=!0}}}},3447:function(e,t,n){"use strict";n.d(t,{J:function(){return i}});var r=n(4117);function i(e){const t=[],n=[];return{OperationDefinition(e){return t.push(e),!1},FragmentDefinition(e){return n.push(e),!1},Document:{leave(){const i=Object.create(null);for(const n of t)for(const t of e.getRecursivelyReferencedFragments(n))i[t.name.value]=!0;for(const t of n){const n=t.name.value;!0!==i[n]&&e.reportError(new r.__(`Fragment "${n}" is never used.`,{nodes:t}))}}}}}},7114:function(e,t,n){"use strict";n.d(t,{p:function(){return i}});var r=n(4117);function i(e){let t=[];return{OperationDefinition:{enter(){t=[]},leave(n){const i=Object.create(null),o=e.getRecursiveVariableUsages(n);for(const{node:e}of o)i[e.name.value]=!0;for(const o of t){const t=o.variable.name.value;!0!==i[t]&&e.reportError(new r.__(n.name?`Variable "$${t}" is never used in operation "${n.name.value}".`:`Variable "$${t}" is never used.`,{nodes:o}))}}},VariableDefinition(e){t.push(e)}}}},7163:function(e,t,n){"use strict";n.d(t,{y:function(){return d}});var r=n(5648),i=n(4117),o=n(3830),a=n(5895),s=n(755),l=n(4034),u=n(5998);function c(e){return Array.isArray(e)?e.map((([e,t])=>`subfields "${e}" conflict because `+c(t))).join(" and "):e}function d(e){const t=new T,n=new Map;return{SelectionSet(r){const o=function(e,t,n,r,i){const o=[],[a,s]=y(e,t,r,i);if(function(e,t,n,r,i){for(const[o,a]of Object.entries(i))if(a.length>1)for(let i=0;i0)return[[t,e.map((([e])=>e))],[n,...e.map((([,e])=>e)).flat()],[r,...e.map((([,,e])=>e)).flat()]]}(r,o,c,b)}}function g(e){var t;const n=null!==(t=e.arguments)&&void 0!==t?t:[],r={kind:o.h.OBJECT,fields:n.map((e=>({kind:o.h.OBJECT_FIELD,name:e.name,value:e.value})))};return(0,a.S)((0,l.n)(r))}function v(e,t){return(0,s.HG)(e)?!(0,s.HG)(t)||v(e.ofType,t.ofType):!!(0,s.HG)(t)||((0,s.zM)(e)?!(0,s.zM)(t)||v(e.ofType,t.ofType):!!(0,s.zM)(t)||!(!(0,s.UT)(e)&&!(0,s.UT)(t))&&e!==t)}function y(e,t,n,r){const i=t.get(r);if(i)return i;const o=Object.create(null),a=Object.create(null);E(e,n,r,o,a);const s=[o,Object.keys(a)];return t.set(r,s),s}function b(e,t,n){const r=t.get(n.selectionSet);if(r)return r;const i=(0,u._)(e.getSchema(),n.typeCondition);return y(e,t,i,n.selectionSet)}function E(e,t,n,r,i){for(const a of n.selections)switch(a.kind){case o.h.FIELD:{const e=a.name.value;let n;((0,s.lp)(t)||(0,s.oT)(t))&&(n=t.getFields()[e]);const i=a.alias?a.alias.value:e;r[i]||(r[i]=[]),r[i].push([t,a,n]);break}case o.h.FRAGMENT_SPREAD:i[a.name.value]=!0;break;case o.h.INLINE_FRAGMENT:{const n=a.typeCondition,o=n?(0,u._)(e.getSchema(),n):t;E(e,o,a.selectionSet,r,i);break}}}class T{constructor(){this._data=new Map}has(e,t,n){var r;const[i,o]=ee.name.value)));for(const n of i.args)if(!a.has(n.name)&&(0,l.dK)(n)){const a=(0,r.X)(n.type);e.reportError(new o.__(`Field "${i.name}" argument "${n.name}" of type "${a}" is required, but it was not provided.`,{nodes:t}))}}}}}function d(e){var t;const n=Object.create(null),c=e.getSchema(),d=null!==(t=null==c?void 0:c.getDirectives())&&void 0!==t?t:u.V4;for(const e of d)n[e.name]=(0,i.P)(e.args.filter(l.dK),(e=>e.name));const p=e.getDocument().definitions;for(const e of p)if(e.kind===a.h.DIRECTIVE_DEFINITION){var h;const t=null!==(h=e.arguments)&&void 0!==h?h:[];n[e.name.value]=(0,i.P)(t.filter(f),(e=>e.name.value))}return{Directive:{leave(t){const i=t.name.value,a=n[i];if(a){var u;const n=null!==(u=t.arguments)&&void 0!==u?u:[],c=new Set(n.map((e=>e.name.value)));for(const[n,u]of Object.entries(a))if(!c.has(n)){const a=(0,l.P9)(u.type)?(0,r.X)(u.type):(0,s.S)(u.type);e.reportError(new o.__(`Directive "@${i}" argument "${n}" of type "${a}" is required, but it was not provided.`,{nodes:t}))}}}}}}function f(e){return e.type.kind===a.h.NON_NULL_TYPE&&null==e.defaultValue}},3989:function(e,t,n){"use strict";n.d(t,{O:function(){return a}});var r=n(5648),i=n(4117),o=n(755);function a(e){return{Field(t){const n=e.getType(),a=t.selectionSet;if(n)if((0,o.UT)((0,o.xC)(n))){if(a){const o=t.name.value,s=(0,r.X)(n);e.reportError(new i.__(`Field "${o}" must not have a selection since type "${s}" has no subfields.`,{nodes:a}))}}else if(!a){const o=t.name.value,a=(0,r.X)(n);e.reportError(new i.__(`Field "${o}" of type "${a}" must have a selection of subfields. Did you mean "${o} { ... }"?`,{nodes:t}))}}}}},9309:function(e,t,n){"use strict";n.d(t,{Z:function(){return a}});var r=n(4117),i=n(3830),o=n(5267);function a(e){return{OperationDefinition(t){if("subscription"===t.operation){const n=e.getSchema(),a=n.getSubscriptionType();if(a){const s=t.name?t.name.value:null,l=Object.create(null),u=e.getDocument(),c=Object.create(null);for(const e of u.definitions)e.kind===i.h.FRAGMENT_DEFINITION&&(c[e.name.value]=e);const d=(0,o.g)(n,c,l,a,t.selectionSet);if(d.size>1){const t=[...d.values()].slice(1).flat();e.reportError(new r.__(null!=s?`Subscription "${s}" must select only one top level field.`:"Anonymous Subscription must select only one top level field.",{nodes:t}))}for(const t of d.values())t[0].name.value.startsWith("__")&&e.reportError(new r.__(null!=s?`Subscription "${s}" must not select an introspection top level field.`:"Anonymous Subscription must not select an introspection top level field.",{nodes:t}))}}}}}},5947:function(e,t,n){"use strict";n.d(t,{L:function(){return o}});var r=n(5839),i=n(4117);function o(e){return{DirectiveDefinition(e){var t;const r=null!==(t=e.arguments)&&void 0!==t?t:[];return n(`@${e.name.value}`,r)},InterfaceTypeDefinition:t,InterfaceTypeExtension:t,ObjectTypeDefinition:t,ObjectTypeExtension:t};function t(e){var t;const r=e.name.value,i=null!==(t=e.fields)&&void 0!==t?t:[];for(const e of i){var o;n(`${r}.${e.name.value}`,null!==(o=e.arguments)&&void 0!==o?o:[])}return!1}function n(t,n){const o=(0,r.v)(n,(e=>e.name.value));for(const[n,r]of o)r.length>1&&e.reportError(new i.__(`Argument "${t}(${n}:)" can only be defined once.`,{nodes:r.map((e=>e.name))}));return!1}}},9168:function(e,t,n){"use strict";n.d(t,{L:function(){return o}});var r=n(5839),i=n(4117);function o(e){return{Field:t,Directive:t};function t(t){var n;const o=null!==(n=t.arguments)&&void 0!==n?n:[],a=(0,r.v)(o,(e=>e.name.value));for(const[t,n]of a)n.length>1&&e.reportError(new i.__(`There can be only one argument named "${t}".`,{nodes:n.map((e=>e.name))}))}}},5681:function(e,t,n){"use strict";n.d(t,{o:function(){return i}});var r=n(4117);function i(e){const t=Object.create(null),n=e.getSchema();return{DirectiveDefinition(i){const o=i.name.value;if(null==n||!n.getDirective(o))return t[o]?e.reportError(new r.__(`There can be only one directive named "@${o}".`,{nodes:[t[o],i.name]})):t[o]=i.name,!1;e.reportError(new r.__(`Directive "@${o}" already exists in the schema. It cannot be redefined.`,{nodes:i.name}))}}}},5673:function(e,t,n){"use strict";n.d(t,{k:function(){return s}});var r=n(4117),i=n(3830),o=n(9615),a=n(5946);function s(e){const t=Object.create(null),n=e.getSchema(),s=n?n.getDirectives():a.V4;for(const e of s)t[e.name]=!e.isRepeatable;const l=e.getDocument().definitions;for(const e of l)e.kind===i.h.DIRECTIVE_DEFINITION&&(t[e.name.value]=!e.repeatable);const u=Object.create(null),c=Object.create(null);return{enter(n){if(!("directives"in n)||!n.directives)return;let a;if(n.kind===i.h.SCHEMA_DEFINITION||n.kind===i.h.SCHEMA_EXTENSION)a=u;else if((0,o.zT)(n)||(0,o.D$)(n)){const e=n.name.value;a=c[e],void 0===a&&(c[e]=a=Object.create(null))}else a=Object.create(null);for(const i of n.directives){const n=i.name.value;t[n]&&(a[n]?e.reportError(new r.__(`The directive "@${n}" can only be used once at this location.`,{nodes:[a[n],i]})):a[n]=i)}}}}},4560:function(e,t,n){"use strict";n.d(t,{L:function(){return o}});var r=n(4117),i=n(755);function o(e){const t=e.getSchema(),n=t?t.getTypeMap():Object.create(null),o=Object.create(null);return{EnumTypeDefinition:a,EnumTypeExtension:a};function a(t){var a;const s=t.name.value;o[s]||(o[s]=Object.create(null));const l=null!==(a=t.values)&&void 0!==a?a:[],u=o[s];for(const t of l){const o=t.name.value,a=n[s];(0,i.EM)(a)&&a.getValue(o)?e.reportError(new r.__(`Enum value "${s}.${o}" already exists in the schema. It cannot also be defined in this type extension.`,{nodes:t.name})):u[o]?e.reportError(new r.__(`Enum value "${s}.${o}" can only be defined once.`,{nodes:[u[o],t.name]})):u[o]=t.name}return!1}}},5240:function(e,t,n){"use strict";n.d(t,{y:function(){return o}});var r=n(4117),i=n(755);function o(e){const t=e.getSchema(),n=t?t.getTypeMap():Object.create(null),i=Object.create(null);return{InputObjectTypeDefinition:o,InputObjectTypeExtension:o,InterfaceTypeDefinition:o,InterfaceTypeExtension:o,ObjectTypeDefinition:o,ObjectTypeExtension:o};function o(t){var o;const s=t.name.value;i[s]||(i[s]=Object.create(null));const l=null!==(o=t.fields)&&void 0!==o?o:[],u=i[s];for(const t of l){const i=t.name.value;a(n[s],i)?e.reportError(new r.__(`Field "${s}.${i}" already exists in the schema. It cannot also be defined in this type extension.`,{nodes:t.name})):u[i]?e.reportError(new r.__(`Field "${s}.${i}" can only be defined once.`,{nodes:[u[i],t.name]})):u[i]=t.name}return!1}}function a(e,t){return!!((0,i.lp)(e)||(0,i.oT)(e)||(0,i.hL)(e))&&null!=e.getFields()[t]}},614:function(e,t,n){"use strict";n.d(t,{N:function(){return i}});var r=n(4117);function i(e){const t=Object.create(null);return{OperationDefinition:()=>!1,FragmentDefinition(n){const i=n.name.value;return t[i]?e.reportError(new r.__(`There can be only one fragment named "${i}".`,{nodes:[t[i],n.name]})):t[i]=n.name,!1}}}},5707:function(e,t,n){"use strict";n.d(t,{P:function(){return o}});var r=n(5052),i=n(4117);function o(e){const t=[];let n=Object.create(null);return{ObjectValue:{enter(){t.push(n),n=Object.create(null)},leave(){const e=t.pop();e||(0,r.k)(!1),n=e}},ObjectField(t){const r=t.name.value;n[r]?e.reportError(new i.__(`There can be only one input field named "${r}".`,{nodes:[n[r],t.name]})):n[r]=t.name}}}},2355:function(e,t,n){"use strict";n.d(t,{H:function(){return i}});var r=n(4117);function i(e){const t=Object.create(null);return{OperationDefinition(n){const i=n.name;return i&&(t[i.value]?e.reportError(new r.__(`There can be only one operation named "${i.value}".`,{nodes:[t[i.value],i]})):t[i.value]=i),!1},FragmentDefinition:()=>!1}}},5427:function(e,t,n){"use strict";n.d(t,{q:function(){return i}});var r=n(4117);function i(e){const t=e.getSchema(),n=Object.create(null),i=t?{query:t.getQueryType(),mutation:t.getMutationType(),subscription:t.getSubscriptionType()}:{};return{SchemaDefinition:o,SchemaExtension:o};function o(t){var o;const a=null!==(o=t.operationTypes)&&void 0!==o?o:[];for(const t of a){const o=t.operation,a=n[o];i[o]?e.reportError(new r.__(`Type for ${o} already defined in the schema. It cannot be redefined.`,{nodes:t})):a?e.reportError(new r.__(`There can be only one ${o} type in schema.`,{nodes:[a,t]})):n[o]=t}return!1}}},4519:function(e,t,n){"use strict";n.d(t,{P:function(){return i}});var r=n(4117);function i(e){const t=Object.create(null),n=e.getSchema();return{ScalarTypeDefinition:i,ObjectTypeDefinition:i,InterfaceTypeDefinition:i,UnionTypeDefinition:i,EnumTypeDefinition:i,InputObjectTypeDefinition:i};function i(i){const o=i.name.value;if(null==n||!n.getType(o))return t[o]?e.reportError(new r.__(`There can be only one type named "${o}".`,{nodes:[t[o],i.name]})):t[o]=i.name,!1;e.reportError(new r.__(`Type "${o}" already exists in the schema. It cannot also be defined in this type definition.`,{nodes:i.name}))}}},7417:function(e,t,n){"use strict";n.d(t,{H:function(){return o}});var r=n(5839),i=n(4117);function o(e){return{OperationDefinition(t){var n;const o=null!==(n=t.variableDefinitions)&&void 0!==n?n:[],a=(0,r.v)(o,(e=>e.variable.name.value));for(const[t,n]of a)n.length>1&&e.reportError(new i.__(`There can be only one variable named "$${t}".`,{nodes:n.map((e=>e.variable.name))}))}}}},4697:function(e,t,n){"use strict";n.d(t,{j:function(){return c}});var r=n(8063),i=n(5648),o=n(9815),a=n(3492),s=n(4117),l=n(5895),u=n(755);function c(e){return{ListValue(t){const n=(0,u.tf)(e.getParentInputType());if(!(0,u.HG)(n))return d(e,t),!1},ObjectValue(t){const n=(0,u.xC)(e.getInputType());if(!(0,u.hL)(n))return d(e,t),!1;const r=(0,o.P)(t.fields,(e=>e.name.value));for(const o of Object.values(n.getFields()))if(!r[o.name]&&(0,u.Wd)(o)){const r=(0,i.X)(o.type);e.reportError(new s.__(`Field "${n.name}.${o.name}" of required type "${r}" was not provided.`,{nodes:t}))}},ObjectField(t){const n=(0,u.xC)(e.getParentInputType());if(!e.getInputType()&&(0,u.hL)(n)){const i=(0,a.D)(t.name.value,Object.keys(n.getFields()));e.reportError(new s.__(`Field "${t.name.value}" is not defined by type "${n.name}".`+(0,r.l)(i),{nodes:t}))}},NullValue(t){const n=e.getInputType();(0,u.zM)(n)&&e.reportError(new s.__(`Expected value of type "${(0,i.X)(n)}", found ${(0,l.S)(t)}.`,{nodes:t}))},EnumValue:t=>d(e,t),IntValue:t=>d(e,t),FloatValue:t=>d(e,t),StringValue:t=>d(e,t),BooleanValue:t=>d(e,t)}}function d(e,t){const n=e.getInputType();if(!n)return;const r=(0,u.xC)(n);if((0,u.UT)(r))try{if(void 0===r.parseLiteral(t,void 0)){const r=(0,i.X)(n);e.reportError(new s.__(`Expected value of type "${r}", found ${(0,l.S)(t)}.`,{nodes:t}))}}catch(r){const o=(0,i.X)(n);r instanceof s.__?e.reportError(r):e.reportError(new s.__(`Expected value of type "${o}", found ${(0,l.S)(t)}; `+r.message,{nodes:t,originalError:r}))}else{const r=(0,i.X)(n);e.reportError(new s.__(`Expected value of type "${r}", found ${(0,l.S)(t)}.`,{nodes:t}))}}},6192:function(e,t,n){"use strict";n.d(t,{I:function(){return s}});var r=n(4117),i=n(5895),o=n(755),a=n(5998);function s(e){return{VariableDefinition(t){const n=(0,a._)(e.getSchema(),t.type);if(void 0!==n&&!(0,o.j$)(n)){const n=t.variable.name.value,o=(0,i.S)(t.type);e.reportError(new r.__(`Variable "$${n}" cannot be non-input type "${o}".`,{nodes:t.type}))}}}}},377:function(e,t,n){"use strict";n.d(t,{w:function(){return u}});var r=n(5648),i=n(4117),o=n(3830),a=n(755),s=n(2984),l=n(5998);function u(e){let t=Object.create(null);return{OperationDefinition:{enter(){t=Object.create(null)},leave(n){const o=e.getRecursiveVariableUsages(n);for(const{node:n,type:a,defaultValue:s}of o){const o=n.name.value,u=t[o];if(u&&a){const t=e.getSchema(),d=(0,l._)(t,u.type);if(d&&!c(t,d,u.defaultValue,a,s)){const t=(0,r.X)(d),s=(0,r.X)(a);e.reportError(new i.__(`Variable "$${o}" of type "${t}" used in position expecting type "${s}".`,{nodes:[u,n]}))}}}}},VariableDefinition(e){t[e.variable.name.value]=e}}}function c(e,t,n,r,i){if((0,a.zM)(r)&&!(0,a.zM)(t)){if((null==n||n.kind===o.h.NULL)&&void 0===i)return!1;const a=r.ofType;return(0,s.uJ)(e,t,a)}return(0,s.uJ)(e,t,r)}},9299:function(e,t,n){"use strict";n.d(t,{M:function(){return j},i:function(){return P}});var r=n(3857),i=n(1870),o=n(5167),a=n(4875),s=n(7513),l=n(1435),u=n(591),c=n(831),d=n(3402),f=n(9316),p=n(9518),h=n(3447),m=n(7114),g=n(7163),v=n(5961),y=n(3721),b=n(16),E=n(3989),T=n(9309),w=n(5947),C=n(9168),S=n(5681),x=n(5673),k=n(4560),N=n(5240),_=n(614),O=n(5707),I=n(2355),D=n(5427),L=n(4519),A=n(7417),M=n(4697),R=n(6192),F=n(377);const P=Object.freeze([r.i,I.H,c.F,T.Z,u.I,o.T,R.I,E.O,i.A,_.N,l.a,h.J,v.a,f.H,A.H,p.$,m.p,s.J,x.k,a.e,C.L,M.j,b.s,F.w,g.y,O.P]),j=Object.freeze([d.t,D.q,L.P,k.L,N.y,w.L,S.o,u.I,s.J,x.k,y.g,a.o,C.L,O.P,b.c])},2780:function(e,t,n){"use strict";n.d(t,{ED:function(){return p},Gu:function(){return c},zo:function(){return f}});var r=n(1172),i=n(4117),o=n(9685),a=n(8555),s=n(1409),l=n(9299),u=n(2716);function c(e,t,n=l.i,c,d=new s.a(e)){var f;const p=null!==(f=null==c?void 0:c.maxErrors)&&void 0!==f?f:100;t||(0,r.a)(!1,"Must provide document."),(0,a.J)(e);const h=Object.freeze({}),m=[],g=new u._t(e,t,d,(e=>{if(m.length>=p)throw m.push(new i.__("Too many validation errors, error limit reached. Validation aborted.")),h;m.push(e)})),v=(0,o.j1)(n.map((e=>e(g))));try{(0,o.Vn)(t,(0,s.y)(d,v))}catch(e){if(e!==h)throw e}return m}function d(e,t,n=l.M){const r=[],i=new u.yv(e,t,(e=>{r.push(e)})),a=n.map((e=>e(i)));return(0,o.Vn)(e,(0,o.j1)(a)),r}function f(e){const t=d(e);if(0!==t.length)throw new Error(t.map((e=>e.message)).join("\n\n"))}function p(e,t){const n=d(e,t);if(0!==n.length)throw new Error(n.map((e=>e.message)).join("\n\n"))}},8488:function(e,t,n){"use strict";n.r(t),n.d(t,{meros:function(){return o}});const r="\r\n\r\n",i=new TextDecoder;async function o(e,t){if(!e.ok||!e.body||e.bodyUsed)return e;const n=e.headers.get("content-type");if(!n||!~n.indexOf("multipart/mixed"))return e;const o=n.indexOf("boundary=");return async function*(e,t,n){const o=e.getReader(),a=!n||!n.multiple;let s="",l=!0,u=[];try{let e;e:for(;!(e=await o.read()).done;){const n=i.decode(e.value),o=n.indexOf(t);let c=s.length;for(s+=n,~o?c+=o:c=s.indexOf(t),u=[];~c;){const e=s.substring(0,c),n=s.substring(c+t.length);if(l)l=!1;else{const t={},i=e.indexOf(r),o=s.slice(0,i).toString().trim().split(/\r\n/);let l;for(;l=o.shift();)l=l.split(": "),t[l.shift().toLowerCase()]=l.join(": ");let c=e.substring(i+r.length,e.lastIndexOf("\r\n")),d=!1;if(l=t["content-type"],l&&~l.indexOf("application/json"))try{c=JSON.parse(c),d=!0}catch(e){}if(l={headers:t,body:c,json:d},a?yield l:u.push(l),"--"===n.substring(0,2))break e}s=n,c=s.indexOf(t)}u.length&&(yield u)}}finally{u.length&&(yield u),o.releaseLock()}}(e.body,`--${~o?n.substring(o+9).trim().replace(/['"]/g,""):"-"}`,t)}},6785:function(e,t,n){"use strict";n.r(t)},5605:function(e,t,n){"use strict";n.r(t)},2162:function(e,t,n){"use strict";n.r(t)},5251:function(e,t,n){"use strict";n.r(t)},9196:function(e){"use strict";e.exports=window.React},1850:function(e){"use strict";e.exports=window.ReactDOM}},r={};function i(e){var t=r[e];if(void 0!==t)return t.exports;var o=r[e]={exports:{}};return n[e].call(o.exports,o,o.exports,i),o.exports}t=Object.getPrototypeOf?function(e){return Object.getPrototypeOf(e)}:function(e){return e.__proto__},i.t=function(n,r){if(1&r&&(n=this(n)),8&r)return n;if("object"==typeof n&&n){if(4&r&&n.__esModule)return n;if(16&r&&"function"==typeof n.then)return n}var o=Object.create(null);i.r(o);var a={};e=e||[null,t({}),t([]),t(t)];for(var s=2&r&&n;"object"==typeof s&&!~e.indexOf(s);s=t(s))Object.getOwnPropertyNames(s).forEach((function(e){a[e]=function(){return n[e]}}));return a.default=function(){return n},i.d(o,a),o},i.d=function(e,t){for(var n in t)i.o(t,n)&&!i.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},i.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.nc=void 0;var o=i(6676);window.GraphiQL=o.default}(); +//# sourceMappingURL=graphiql.min.js.map \ No newline at end of file diff --git a/graphql/internal/graphiql/index.html b/graphql/internal/graphiql/index.html new file mode 100644 index 0000000000..fabe61e7f2 --- /dev/null +++ b/graphql/internal/graphiql/index.html @@ -0,0 +1,46 @@ + + + + + GraphiQL + + + + + + + + + +
Loading...
+ + + + \ No newline at end of file diff --git a/graphql/internal/graphiql/react-dom.production.min.js b/graphql/internal/graphiql/react-dom.production.min.js new file mode 100644 index 0000000000..e38d120b23 --- /dev/null +++ b/graphql/internal/graphiql/react-dom.production.min.js @@ -0,0 +1,245 @@ +/** @license React v17.0.2 + * react-dom.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +(function(){/* + Modernizr 3.0.0pre (Custom Build) | MIT +*/ +'use strict';(function(M,ha){"object"===typeof exports&&"undefined"!==typeof module?ha(exports,require("react")):"function"===typeof define&&define.amd?define(["exports","react"],ha):(M=M||self,ha(M.ReactDOM={},M.React))})(this,function(M,ha){function m(a){for(var b="https://reactjs.org/docs/error-decoder.html?invariant="+a,c=1;cb}return!1}function Q(a,b,c,d,e,f,g){this.acceptsBooleans=2===b||3===b||4===b;this.attributeName=d;this.attributeNamespace=e;this.mustUseProperty=c;this.propertyName=a;this.type=b;this.sanitizeURL=f;this.removeEmptyString=g}function Ed(a,b,c,d){var e=I.hasOwnProperty(b)?I[b]:null;var f=null!==e?0===e.type:d?!1:!(2h||e[g]!==f[h])return"\n"+e[g].replace(" at new "," at ");while(1<=g&&0<=h)}break}}}finally{Gd=!1,Error.prepareStackTrace=c}return(a=a?a.displayName||a.name:"")?Kb(a):""}function pi(a){switch(a.tag){case 5:return Kb(a.type);case 16:return Kb("Lazy");case 13:return Kb("Suspense"); +case 19:return Kb("SuspenseList");case 0:case 2:case 15:return a=Bc(a.type,!1),a;case 11:return a=Bc(a.type.render,!1),a;case 22:return a=Bc(a.type._render,!1),a;case 1:return a=Bc(a.type,!0),a;default:return""}}function hb(a){if(null==a)return null;if("function"===typeof a)return a.displayName||a.name||null;if("string"===typeof a)return a;switch(a){case wa:return"Fragment";case Ua:return"Portal";case Lb:return"Profiler";case Hd:return"StrictMode";case Mb:return"Suspense";case Cc:return"SuspenseList"}if("object"=== +typeof a)switch(a.$$typeof){case Id:return(a.displayName||"Context")+".Consumer";case Jd:return(a._context.displayName||"Context")+".Provider";case Dc:var b=a.render;b=b.displayName||b.name||"";return a.displayName||(""!==b?"ForwardRef("+b+")":"ForwardRef");case Ec:return hb(a.type);case Kd:return hb(a._render);case Ld:b=a._payload;a=a._init;try{return hb(a(b))}catch(c){}}return null}function xa(a){switch(typeof a){case "boolean":case "number":case "object":case "string":case "undefined":return a; +default:return""}}function Ef(a){var b=a.type;return(a=a.nodeName)&&"input"===a.toLowerCase()&&("checkbox"===b||"radio"===b)}function qi(a){var b=Ef(a)?"checked":"value",c=Object.getOwnPropertyDescriptor(a.constructor.prototype,b),d=""+a[b];if(!a.hasOwnProperty(b)&&"undefined"!==typeof c&&"function"===typeof c.get&&"function"===typeof c.set){var e=c.get,f=c.set;Object.defineProperty(a,b,{configurable:!0,get:function(){return e.call(this)},set:function(a){d=""+a;f.call(this,a)}});Object.defineProperty(a, +b,{enumerable:c.enumerable});return{getValue:function(){return d},setValue:function(a){d=""+a},stopTracking:function(){a._valueTracker=null;delete a[b]}}}}function Fc(a){a._valueTracker||(a._valueTracker=qi(a))}function Ff(a){if(!a)return!1;var b=a._valueTracker;if(!b)return!0;var c=b.getValue();var d="";a&&(d=Ef(a)?a.checked?"true":"false":a.value);a=d;return a!==c?(b.setValue(a),!0):!1}function Gc(a){a=a||("undefined"!==typeof document?document:void 0);if("undefined"===typeof a)return null;try{return a.activeElement|| +a.body}catch(b){return a.body}}function Md(a,b){var c=b.checked;return B({},b,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:null!=c?c:a._wrapperState.initialChecked})}function Gf(a,b){var c=null==b.defaultValue?"":b.defaultValue,d=null!=b.checked?b.checked:b.defaultChecked;c=xa(null!=b.value?b.value:c);a._wrapperState={initialChecked:d,initialValue:c,controlled:"checkbox"===b.type||"radio"===b.type?null!=b.checked:null!=b.value}}function Hf(a,b){b=b.checked;null!=b&&Ed(a,"checked", +b,!1)}function Nd(a,b){Hf(a,b);var c=xa(b.value),d=b.type;if(null!=c)if("number"===d){if(0===c&&""===a.value||a.value!=c)a.value=""+c}else a.value!==""+c&&(a.value=""+c);else if("submit"===d||"reset"===d){a.removeAttribute("value");return}b.hasOwnProperty("value")?Od(a,b.type,c):b.hasOwnProperty("defaultValue")&&Od(a,b.type,xa(b.defaultValue));null==b.checked&&null!=b.defaultChecked&&(a.defaultChecked=!!b.defaultChecked)}function If(a,b,c){if(b.hasOwnProperty("value")||b.hasOwnProperty("defaultValue")){var d= +b.type;if(!("submit"!==d&&"reset"!==d||void 0!==b.value&&null!==b.value))return;b=""+a._wrapperState.initialValue;c||b===a.value||(a.value=b);a.defaultValue=b}c=a.name;""!==c&&(a.name="");a.defaultChecked=!!a._wrapperState.initialChecked;""!==c&&(a.name=c)}function Od(a,b,c){if("number"!==b||Gc(a.ownerDocument)!==a)null==c?a.defaultValue=""+a._wrapperState.initialValue:a.defaultValue!==""+c&&(a.defaultValue=""+c)}function ri(a){var b="";ha.Children.forEach(a,function(a){null!=a&&(b+=a)});return b} +function Pd(a,b){a=B({children:void 0},b);if(b=ri(b.children))a.children=b;return a}function ib(a,b,c,d){a=a.options;if(b){b={};for(var e=0;e=c.length))throw Error(m(93));c=c[0]}b=c}null==b&&(b="");c=b}a._wrapperState={initialValue:xa(c)}}function Kf(a,b){var c=xa(b.value),d=xa(b.defaultValue);null!=c&&(c=""+c,c!==a.value&&(a.value=c),null==b.defaultValue&&a.defaultValue!== +c&&(a.defaultValue=c));null!=d&&(a.defaultValue=""+d)}function Lf(a,b){b=a.textContent;b===a._wrapperState.initialValue&&""!==b&&null!==b&&(a.value=b)}function Mf(a){switch(a){case "svg":return"http://www.w3.org/2000/svg";case "math":return"http://www.w3.org/1998/Math/MathML";default:return"http://www.w3.org/1999/xhtml"}}function Rd(a,b){return null==a||"http://www.w3.org/1999/xhtml"===a?Mf(b):"http://www.w3.org/2000/svg"===a&&"foreignObject"===b?"http://www.w3.org/1999/xhtml":a}function Nf(a,b,c){return null== +b||"boolean"===typeof b||""===b?"":c||"number"!==typeof b||0===b||Nb.hasOwnProperty(a)&&Nb[a]?(""+b).trim():b+"px"}function Of(a,b){a=a.style;for(var c in b)if(b.hasOwnProperty(c)){var d=0===c.indexOf("--"),e=Nf(c,b[c],d);"float"===c&&(c="cssFloat");d?a.setProperty(c,e):a[c]=e}}function Sd(a,b){if(b){if(si[a]&&(null!=b.children||null!=b.dangerouslySetInnerHTML))throw Error(m(137,a));if(null!=b.dangerouslySetInnerHTML){if(null!=b.children)throw Error(m(60));if(!("object"===typeof b.dangerouslySetInnerHTML&& +"__html"in b.dangerouslySetInnerHTML))throw Error(m(61));}if(null!=b.style&&"object"!==typeof b.style)throw Error(m(62));}}function Td(a,b){if(-1===a.indexOf("-"))return"string"===typeof b.is;switch(a){case "annotation-xml":case "color-profile":case "font-face":case "font-face-src":case "font-face-uri":case "font-face-format":case "font-face-name":case "missing-glyph":return!1;default:return!0}}function Ud(a){a=a.target||a.srcElement||window;a.correspondingUseElement&&(a=a.correspondingUseElement); +return 3===a.nodeType?a.parentNode:a}function Pf(a){if(a=Ob(a)){if("function"!==typeof Vd)throw Error(m(280));var b=a.stateNode;b&&(b=Hc(b),Vd(a.stateNode,a.type,b))}}function Qf(a){jb?kb?kb.push(a):kb=[a]:jb=a}function Rf(){if(jb){var a=jb,b=kb;kb=jb=null;Pf(a);if(b)for(a=0;ad?0:1<c;c++)b.push(a);return b}function Oc(a,b,c){a.pendingLanes|=b;var d=b-1;a.suspendedLanes&=d;a.pingedLanes&=d;a=a.eventTimes;b=31-Ba(b);a[b]=c}function Hi(a){return 0===a?32:31-(Ii(a)/Ji|0)|0}function Ki(a,b,c,d){Xa||Xd();var e=he,f=Xa;Xa=!0;try{fg(e,a,b,c,d)}finally{(Xa=f)||Wd()}}function Li(a,b,c,d){Mi(Ni,he.bind(null,a,b,c,d))}function he(a, +b,c,d){if(Pc){var e;if((e=0===(b&4))&&0=b)return{node:c,offset:b-a};a=d}a:{for(;c;){if(c.nextSibling){c=c.nextSibling;break a}c=c.parentNode}c=void 0}c=ug(c)}}function wg(a,b){return a&&b?a===b?!0:a&&3===a.nodeType?!1:b&&3===b.nodeType?wg(a,b.parentNode):"contains"in a?a.contains(b):a.compareDocumentPosition?!!(a.compareDocumentPosition(b)&16):!1:!1}function xg(){for(var a=window,b=Gc();b instanceof a.HTMLIFrameElement;){try{var c= +"string"===typeof b.contentWindow.location.href}catch(d){c=!1}if(c)a=b.contentWindow;else break;b=Gc(a.document)}return b}function ne(a){var b=a&&a.nodeName&&a.nodeName.toLowerCase();return b&&("input"===b&&("text"===a.type||"search"===a.type||"tel"===a.type||"url"===a.type||"password"===a.type)||"textarea"===b||"true"===a.contentEditable)}function yg(a,b,c){var d=c.window===c?c.document:9===c.nodeType?c:c.ownerDocument;oe||null==qb||qb!==Gc(d)||(d=qb,"selectionStart"in d&&ne(d)?d={start:d.selectionStart, +end:d.selectionEnd}:(d=(d.ownerDocument&&d.ownerDocument.defaultView||window).getSelection(),d={anchorNode:d.anchorNode,anchorOffset:d.anchorOffset,focusNode:d.focusNode,focusOffset:d.focusOffset}),$b&&Zb($b,d)||($b=d,d=Tc(pe,"onSelect"),0ub||(a.current=ve[ub],ve[ub]=null,ub--)}function A(a,b,c){ub++;ve[ub]=a.current;a.current=b}function vb(a,b){var c=a.type.contextTypes;if(!c)return Ha;var d=a.stateNode;if(d&&d.__reactInternalMemoizedUnmaskedChildContext===b)return d.__reactInternalMemoizedMaskedChildContext;var e={},f;for(f in c)e[f]=b[f];d&&(a=a.stateNode,a.__reactInternalMemoizedUnmaskedChildContext= +b,a.__reactInternalMemoizedMaskedChildContext=e);return e}function S(a){a=a.childContextTypes;return null!==a&&void 0!==a}function Sg(a,b,c){if(D.current!==Ha)throw Error(m(168));A(D,b);A(J,c)}function Tg(a,b,c){var d=a.stateNode;a=b.childContextTypes;if("function"!==typeof d.getChildContext)return c;d=d.getChildContext();for(var e in d)if(!(e in a))throw Error(m(108,hb(b)||"Unknown",e));return B({},c,d)}function Xc(a){a=(a=a.stateNode)&&a.__reactInternalMemoizedMergedChildContext||Ha;Ya=D.current; +A(D,a);A(J,J.current);return!0}function Ug(a,b,c){var d=a.stateNode;if(!d)throw Error(m(169));c?(a=Tg(a,b,Ya),d.__reactInternalMemoizedMergedChildContext=a,t(J),t(D),A(D,a)):t(J);A(J,c)}function wb(){switch(oj()){case Yc:return 99;case Vg:return 98;case Wg:return 97;case Xg:return 96;case Yg:return 95;default:throw Error(m(332));}}function Zg(a){switch(a){case 99:return Yc;case 98:return Vg;case 97:return Wg;case 96:return Xg;case 95:return Yg;default:throw Error(m(332));}}function Za(a,b){a=Zg(a); +return pj(a,b)}function bc(a,b,c){a=Zg(a);return we(a,b,c)}function ja(){if(null!==Zc){var a=Zc;Zc=null;xe(a)}$g()}function $g(){if(!ye&&null!==pa){ye=!0;var a=0;try{var b=pa;Za(99,function(){for(;ap?(x=l,l=null):x=l.sibling;var C=r(e,l,h[p],k);if(null===C){null===l&&(l=x);break}a&&l&&null=== +C.alternate&&b(e,l);g=f(C,g,p);null===v?m=C:v.sibling=C;v=C;l=x}if(p===h.length)return c(e,l),m;if(null===l){for(;px?(C=p,p=null):C=p.sibling;var Da=r(e,p,q.value,k);if(null===Da){null===p&&(p=C);break}a&&p&&null===Da.alternate&&b(e,p);g=f(Da,g,x);null===v?l=Da:v.sibling=Da;v=Da;p=C}if(q.done)return c(e,p),l;if(null===p){for(;!q.done;x++,q=h.next())q=n(e,q.value,k),null!==q&&(g=f(q,g,x),null===v?l=q:v.sibling=q,v=q);return l}for(p=d(e,p);!q.done;x++,q=h.next())q=t(p,e,x,q.value,k),null!==q&&(a&&null!== +q.alternate&&p.delete(null===q.key?x:q.key),g=f(q,g,x),null===v?l=q:v.sibling=q,v=q);a&&p.forEach(function(a){return b(e,a)});return l}return function(a,d,f,h){var k="object"===typeof f&&null!==f&&f.type===wa&&null===f.key;k&&(f=f.props.children);var l="object"===typeof f&&null!==f;if(l)switch(f.$$typeof){case ec:a:{l=f.key;for(k=d;null!==k;){if(k.key===l){switch(k.tag){case 7:if(f.type===wa){c(a,k.sibling);d=e(k,f.props.children);d.return=a;a=d;break a}break;default:if(k.elementType===f.type){c(a, +k.sibling);d=e(k,f.props);d.ref=dc(a,k,f);d.return=a;a=d;break a}}c(a,k);break}else b(a,k);k=k.sibling}f.type===wa?(d=zb(f.props.children,a.mode,h,f.key),d.return=a,a=d):(h=fd(f.type,f.key,f.props,null,a.mode,h),h.ref=dc(a,d,f),h.return=a,a=h)}return g(a);case Ua:a:{for(k=f.key;null!==d;){if(d.key===k)if(4===d.tag&&d.stateNode.containerInfo===f.containerInfo&&d.stateNode.implementation===f.implementation){c(a,d.sibling);d=e(d,f.children||[]);d.return=a;a=d;break a}else{c(a,d);break}else b(a,d);d= +d.sibling}d=Ee(f,a.mode,h);d.return=a;a=d}return g(a)}if("string"===typeof f||"number"===typeof f)return f=""+f,null!==d&&6===d.tag?(c(a,d.sibling),d=e(d,f),d.return=a,a=d):(c(a,d),d=De(f,a.mode,h),d.return=a,a=d),g(a);if(gd(f))return w(a,d,f,h);if(Jb(f))return z(a,d,f,h);l&&ed(a,f);if("undefined"===typeof f&&!k)switch(a.tag){case 1:case 22:case 0:case 11:case 15:throw Error(m(152,hb(a.type)||"Component"));}return c(a,d)}}function $a(a){if(a===fc)throw Error(m(174));return a}function Fe(a,b){A(gc, +b);A(hc,a);A(ka,fc);a=b.nodeType;switch(a){case 9:case 11:b=(b=b.documentElement)?b.namespaceURI:Rd(null,"");break;default:a=8===a?b.parentNode:b,b=a.namespaceURI||null,a=a.tagName,b=Rd(b,a)}t(ka);A(ka,b)}function Ab(a){t(ka);t(hc);t(gc)}function jh(a){$a(gc.current);var b=$a(ka.current);var c=Rd(b,a.type);b!==c&&(A(hc,a),A(ka,c))}function Ge(a){hc.current===a&&(t(ka),t(hc))}function hd(a){for(var b=a;null!==b;){if(13===b.tag){var c=b.memoizedState;if(null!==c&&(c=c.dehydrated,null===c||"$?"===c.data|| +"$!"===c.data))return b}else if(19===b.tag&&void 0!==b.memoizedProps.revealOrder){if(0!==(b.flags&64))return b}else if(null!==b.child){b.child.return=b;b=b.child;continue}if(b===a)break;for(;null===b.sibling;){if(null===b.return||b.return===a)return null;b=b.return}b.sibling.return=b.return;b=b.sibling}return null}function kh(a,b){var c=Z(5,null,null,0);c.elementType="DELETED";c.type="DELETED";c.stateNode=b;c.return=a;c.flags=8;null!==a.lastEffect?(a.lastEffect.nextEffect=c,a.lastEffect=c):a.firstEffect= +a.lastEffect=c}function lh(a,b){switch(a.tag){case 5:var c=a.type;b=1!==b.nodeType||c.toLowerCase()!==b.nodeName.toLowerCase()?null:b;return null!==b?(a.stateNode=b,!0):!1;case 6:return b=""===a.pendingProps||3!==b.nodeType?null:b,null!==b?(a.stateNode=b,!0):!1;case 13:return!1;default:return!1}}function He(a){if(la){var b=Na;if(b){var c=b;if(!lh(a,b)){b=tb(c.nextSibling);if(!b||!lh(a,b)){a.flags=a.flags&-1025|2;la=!1;ra=a;return}kh(ra,c)}ra=a;Na=tb(b.firstChild)}else a.flags=a.flags&-1025|2,la=!1, +ra=a}}function mh(a){for(a=a.return;null!==a&&5!==a.tag&&3!==a.tag&&13!==a.tag;)a=a.return;ra=a}function id(a){if(a!==ra)return!1;if(!la)return mh(a),la=!0,!1;var b=a.type;if(5!==a.tag||"head"!==b&&"body"!==b&&!se(b,a.memoizedProps))for(b=Na;b;)kh(a,b),b=tb(b.nextSibling);mh(a);if(13===a.tag){a=a.memoizedState;a=null!==a?a.dehydrated:null;if(!a)throw Error(m(317));a:{a=a.nextSibling;for(b=0;a;){if(8===a.nodeType){var c=a.data;if("/$"===c){if(0===b){Na=tb(a.nextSibling);break a}b--}else"$"!==c&&"$!"!== +c&&"$?"!==c||b++}a=a.nextSibling}Na=null}}else Na=ra?tb(a.stateNode.nextSibling):null;return!0}function Ie(){Na=ra=null;la=!1}function Je(){for(var a=0;af))throw Error(m(301));f+=1;K=N=null;b.updateQueue=null;jc.current=sj;a=c(d,e)}while(kc)}jc.current=jd;b=null!==N&&null!==N.next;ic=0;K=N=y=null;kd=!1;if(b)throw Error(m(300));return a}function ab(){var a={memoizedState:null,baseState:null,baseQueue:null,queue:null,next:null};null===K?y.memoizedState=K=a:K=K.next=a;return K}function bb(){if(null===N){var a=y.alternate;a=null!==a?a.memoizedState:null}else a=N.next;var b=null===K?y.memoizedState:K.next;if(null!== +b)K=b,N=a;else{if(null===a)throw Error(m(310));N=a;a={memoizedState:N.memoizedState,baseState:N.baseState,baseQueue:N.baseQueue,queue:N.queue,next:null};null===K?y.memoizedState=K=a:K=K.next=a}return K}function ma(a,b){return"function"===typeof b?b(a):b}function lc(a,b,c){b=bb();c=b.queue;if(null===c)throw Error(m(311));c.lastRenderedReducer=a;var d=N,e=d.baseQueue,f=c.pending;if(null!==f){if(null!==e){var g=e.next;e.next=f.next;f.next=g}d.baseQueue=e=f;c.pending=null}if(null!==e){e=e.next;d=d.baseState; +var h=g=f=null,k=e;do{var l=k.lane;if((ic&l)===l)null!==h&&(h=h.next={lane:0,action:k.action,eagerReducer:k.eagerReducer,eagerState:k.eagerState,next:null}),d=k.eagerReducer===a?k.eagerState:a(d,k.action);else{var n={lane:l,action:k.action,eagerReducer:k.eagerReducer,eagerState:k.eagerState,next:null};null===h?(g=h=n,f=d):h=h.next=n;y.lanes|=l;La|=l}k=k.next}while(null!==k&&k!==e);null===h?f=d:h.next=g;X(d,b.memoizedState)||(fa=!0);b.memoizedState=d;b.baseState=f;b.baseQueue=h;c.lastRenderedState= +d}return[b.memoizedState,c.dispatch]}function mc(a,b,c){b=bb();c=b.queue;if(null===c)throw Error(m(311));c.lastRenderedReducer=a;var d=c.dispatch,e=c.pending,f=b.memoizedState;if(null!==e){c.pending=null;var g=e=e.next;do f=a(f,g.action),g=g.next;while(g!==e);X(f,b.memoizedState)||(fa=!0);b.memoizedState=f;null===b.baseQueue&&(b.baseState=f);c.lastRenderedState=f}return[f,d]}function nh(a,b,c){var d=b._getVersion;d=d(b._source);var e=b._workInProgressVersionPrimary;if(null!==e)a=e===d;else if(a=a.mutableReadLanes, +a=(ic&a)===a)b._workInProgressVersionPrimary=d,Bb.push(b);if(a)return c(b._source);Bb.push(b);throw Error(m(350));}function oh(a,b,c,d){var e=R;if(null===e)throw Error(m(349));var f=b._getVersion,g=f(b._source),h=jc.current,k=h.useState(function(){return nh(e,b,c)}),l=k[1],n=k[0];k=K;var t=a.memoizedState,r=t.refs,w=r.getSnapshot,z=t.source;t=t.subscribe;var B=y;a.memoizedState={refs:r,source:b,subscribe:d};h.useEffect(function(){r.getSnapshot=c;r.setSnapshot=l;var a=f(b._source);if(!X(g,a)){a=c(b._source); +X(n,a)||(l(a),a=Oa(B),e.mutableReadLanes|=a&e.pendingLanes);a=e.mutableReadLanes;e.entangledLanes|=a;for(var d=e.entanglements,h=a;0c?98:c,function(){a(!0)});Za(97\x3c/script>",a=a.removeChild(a.firstChild)):"string"===typeof d.is?a=g.createElement(c,{is:d.is}):(a=g.createElement(c),"select"===c&&(g=a,d.multiple? +g.multiple=!0:d.size&&(g.size=d.size))):a=g.createElementNS(a,c);a[Fa]=b;a[Wc]=d;xj(a,b,!1,!1);b.stateNode=a;g=Td(c,d);switch(c){case "dialog":z("cancel",a);z("close",a);e=d;break;case "iframe":case "object":case "embed":z("load",a);e=d;break;case "video":case "audio":for(e=0;eWe&&(b.flags|=64,f=!0,oc(d,!1),b.lanes=33554432)}else{if(!f)if(a=hd(g),null!==a){if(b.flags|=64,f=!0,c=a.updateQueue,null!==c&&(b.updateQueue=c,b.flags|=4),oc(d,!0),null===d.tail&&"hidden"===d.tailMode&& +!g.alternate&&!la)return b=b.lastEffect=d.lastEffect,null!==b&&(b.nextEffect=null),null}else 2*P()-d.renderingStartTime>We&&1073741824!==c&&(b.flags|=64,f=!0,oc(d,!1),b.lanes=33554432);d.isBackwards?(g.sibling=b.child,b.child=g):(c=d.last,null!==c?c.sibling=g:b.child=g,d.last=g)}return null!==d.tail?(c=d.tail,d.rendering=c,d.tail=c.sibling,d.lastEffect=b.lastEffect,d.renderingStartTime=P(),c.sibling=null,b=E.current,A(E,f?b&1|2:b&1),c):null;case 23:case 24:return ta=cb.current,t(cb),null!==a&&null!== +a.memoizedState!==(null!==b.memoizedState)&&"unstable-defer-without-hiding"!==d.mode&&(b.flags|=4),null}throw Error(m(156,b.tag));}function zj(a,b){switch(a.tag){case 1:return S(a.type)&&(t(J),t(D)),b=a.flags,b&4096?(a.flags=b&-4097|64,a):null;case 3:Ab();t(J);t(D);Je();b=a.flags;if(0!==(b&64))throw Error(m(285));a.flags=b&-4097|64;return a;case 5:return Ge(a),null;case 13:return t(E),b=a.flags,b&4096?(a.flags=b&-4097|64,a):null;case 19:return t(E),null;case 4:return Ab(),null;case 10:return Ae(a), +null;case 23:case 24:return ta=cb.current,t(cb),null;default:return null}}function Xe(a,b){try{var c="",d=b;do c+=pi(d),d=d.return;while(d);var e=c}catch(f){e="\nError generating stack: "+f.message+"\n"+f.stack}return{value:a,source:b,stack:e}}function Ye(a,b){try{console.error(b.value)}catch(c){setTimeout(function(){throw c;})}}function Mh(a,b,c){c=Ia(-1,c);c.tag=3;c.payload={element:null};var d=b.value;c.callback=function(){rd||(rd=!0,Ze=d);Ye(a,b)};return c}function Nh(a,b,c){c=Ia(-1,c);c.tag= +3;var d=a.type.getDerivedStateFromError;if("function"===typeof d){var e=b.value;c.payload=function(){Ye(a,b);return d(e)}}var f=a.stateNode;null!==f&&"function"===typeof f.componentDidCatch&&(c.callback=function(){"function"!==typeof d&&(null===na?na=new Set([this]):na.add(this),Ye(a,b));var c=b.stack;this.componentDidCatch(b.value,{componentStack:null!==c?c:""})});return c}function Oh(a){var b=a.ref;if(null!==b)if("function"===typeof b)try{b(null)}catch(c){Qa(a,c)}else b.current=null}function Aj(a, +b){switch(b.tag){case 0:case 11:case 15:case 22:return;case 1:if(b.flags&256&&null!==a){var c=a.memoizedProps,d=a.memoizedState;a=b.stateNode;b=a.getSnapshotBeforeUpdate(b.elementType===b.type?c:ea(b.type,c),d);a.__reactInternalSnapshotBeforeUpdate=b}return;case 3:b.flags&256&&te(b.stateNode.containerInfo);return;case 5:case 6:case 4:case 17:return}throw Error(m(163));}function Bj(a,b,c,d){switch(c.tag){case 0:case 11:case 15:case 22:b=c.updateQueue;b=null!==b?b.lastEffect:null;if(null!==b){a=b=b.next; +do 3===(a.tag&3)&&(d=a.create,a.destroy=d()),a=a.next;while(a!==b)}b=c.updateQueue;b=null!==b?b.lastEffect:null;if(null!==b){a=b=b.next;do{var e=a;d=e.next;e=e.tag;0!==(e&4)&&0!==(e&1)&&(Ph(c,a),Cj(c,a));a=d}while(a!==b)}return;case 1:a=c.stateNode;c.flags&4&&(null===b?a.componentDidMount():(d=c.elementType===c.type?b.memoizedProps:ea(c.type,b.memoizedProps),a.componentDidUpdate(d,b.memoizedState,a.__reactInternalSnapshotBeforeUpdate)));b=c.updateQueue;null!==b&&dh(c,b,a);return;case 3:b=c.updateQueue; +if(null!==b){a=null;if(null!==c.child)switch(c.child.tag){case 5:a=c.child.stateNode;break;case 1:a=c.child.stateNode}dh(c,b,a)}return;case 5:a=c.stateNode;null===b&&c.flags&4&&Pg(c.type,c.memoizedProps)&&a.focus();return;case 6:return;case 4:return;case 12:return;case 13:null===c.memoizedState&&(c=c.alternate,null!==c&&(c=c.memoizedState,null!==c&&(c=c.dehydrated,null!==c&&bg(c))));return;case 19:case 17:case 20:case 21:case 23:case 24:return}throw Error(m(163));}function Qh(a,b){for(var c=a;;){if(5=== +c.tag){var d=c.stateNode;if(b)d=d.style,"function"===typeof d.setProperty?d.setProperty("display","none","important"):d.display="none";else{d=c.stateNode;var e=c.memoizedProps.style;e=void 0!==e&&null!==e&&e.hasOwnProperty("display")?e.display:null;d.style.display=Nf("display",e)}}else if(6===c.tag)c.stateNode.nodeValue=b?"":c.memoizedProps;else if((23!==c.tag&&24!==c.tag||null===c.memoizedState||c===a)&&null!==c.child){c.child.return=c;c=c.child;continue}if(c===a)break;for(;null===c.sibling;){if(null=== +c.return||c.return===a)return;c=c.return}c.sibling.return=c.return;c=c.sibling}}function Rh(a,b,c){if(db&&"function"===typeof db.onCommitFiberUnmount)try{db.onCommitFiberUnmount($e,b)}catch(f){}switch(b.tag){case 0:case 11:case 14:case 15:case 22:a=b.updateQueue;if(null!==a&&(a=a.lastEffect,null!==a)){c=a=a.next;do{var d=c,e=d.destroy;d=d.tag;if(void 0!==e)if(0!==(d&4))Ph(b,c);else{d=b;try{e()}catch(f){Qa(d,f)}}c=c.next}while(c!==a)}break;case 1:Oh(b);a=b.stateNode;if("function"===typeof a.componentWillUnmount)try{a.props= +b.memoizedProps,a.state=b.memoizedState,a.componentWillUnmount()}catch(f){Qa(b,f)}break;case 5:Oh(b);break;case 4:Sh(a,b)}}function Th(a){a.alternate=null;a.child=null;a.dependencies=null;a.firstEffect=null;a.lastEffect=null;a.memoizedProps=null;a.memoizedState=null;a.pendingProps=null;a.return=null;a.updateQueue=null}function Uh(a){return 5===a.tag||3===a.tag||4===a.tag}function Vh(a){a:{for(var b=a.return;null!==b;){if(Uh(b))break a;b=b.return}throw Error(m(160));}var c=b;b=c.stateNode;switch(c.tag){case 5:var d= +!1;break;case 3:b=b.containerInfo;d=!0;break;case 4:b=b.containerInfo;d=!0;break;default:throw Error(m(161));}c.flags&16&&(qc(b,""),c.flags&=-17);a:b:for(c=a;;){for(;null===c.sibling;){if(null===c.return||Uh(c.return)){c=null;break a}c=c.return}c.sibling.return=c.return;for(c=c.sibling;5!==c.tag&&6!==c.tag&&18!==c.tag;){if(c.flags&2)continue b;if(null===c.child||4===c.tag)continue b;else c.child.return=c,c=c.child}if(!(c.flags&2)){c=c.stateNode;break a}}d?af(a,c,b):bf(a,c,b)}function af(a,b,c){var d= +a.tag,e=5===d||6===d;if(e)a=e?a.stateNode:a.stateNode.instance,b?8===c.nodeType?c.parentNode.insertBefore(a,b):c.insertBefore(a,b):(8===c.nodeType?(b=c.parentNode,b.insertBefore(a,c)):(b=c,b.appendChild(a)),c=c._reactRootContainer,null!==c&&void 0!==c||null!==b.onclick||(b.onclick=Vc));else if(4!==d&&(a=a.child,null!==a))for(af(a,b,c),a=a.sibling;null!==a;)af(a,b,c),a=a.sibling}function bf(a,b,c){var d=a.tag,e=5===d||6===d;if(e)a=e?a.stateNode:a.stateNode.instance,b?c.insertBefore(a,b):c.appendChild(a); +else if(4!==d&&(a=a.child,null!==a))for(bf(a,b,c),a=a.sibling;null!==a;)bf(a,b,c),a=a.sibling}function Sh(a,b,c){c=b;for(var d=!1,e,f;;){if(!d){e=c.return;a:for(;;){if(null===e)throw Error(m(160));f=e.stateNode;switch(e.tag){case 5:e=f;f=!1;break a;case 3:e=f.containerInfo;f=!0;break a;case 4:e=f.containerInfo;f=!0;break a}e=e.return}d=!0}if(5===c.tag||6===c.tag){a:for(var g=a,h=c,k=h;;)if(Rh(g,k),null!==k.child&&4!==k.tag)k.child.return=k,k=k.child;else{if(k===h)break a;for(;null===k.sibling;){if(null=== +k.return||k.return===h)break a;k=k.return}k.sibling.return=k.return;k=k.sibling}f?(g=e,h=c.stateNode,8===g.nodeType?g.parentNode.removeChild(h):g.removeChild(h)):e.removeChild(c.stateNode)}else if(4===c.tag){if(null!==c.child){e=c.stateNode.containerInfo;f=!0;c.child.return=c;c=c.child;continue}}else if(Rh(a,c),null!==c.child){c.child.return=c;c=c.child;continue}if(c===b)break;for(;null===c.sibling;){if(null===c.return||c.return===b)return;c=c.return;4===c.tag&&(d=!1)}c.sibling.return=c.return;c= +c.sibling}}function cf(a,b){switch(b.tag){case 0:case 11:case 14:case 15:case 22:var c=b.updateQueue;c=null!==c?c.lastEffect:null;if(null!==c){var d=c=c.next;do 3===(d.tag&3)&&(a=d.destroy,d.destroy=void 0,void 0!==a&&a()),d=d.next;while(d!==c)}return;case 1:return;case 5:c=b.stateNode;if(null!=c){d=b.memoizedProps;var e=null!==a?a.memoizedProps:d;a=b.type;var f=b.updateQueue;b.updateQueue=null;if(null!==f){c[Wc]=d;"input"===a&&"radio"===d.type&&null!=d.name&&Hf(c,d);Td(a,e);b=Td(a,d);for(e=0;ee&&(e=g);c&=~f}c=e;c=P()-c;c=(120>c?120:480>c?480:1080>c?1080:1920>c?1920:3E3>c?3E3:4320>c?4320:1960*Ij(c/1960))-c;if(10 component higher in the tree to provide a loading indicator or placeholder to display.")}5!== +L&&(L=2);k=Xe(k,h);r=g;do{switch(r.tag){case 3:f=k;r.flags|=4096;b&=-b;r.lanes|=b;var B=Mh(r,f,b);ch(r,B);break a;case 1:f=k;var A=r.type,D=r.stateNode;if(0===(r.flags&64)&&("function"===typeof A.getDerivedStateFromError||null!==D&&"function"===typeof D.componentDidCatch&&(null===na||!na.has(D)))){r.flags|=4096;b&=-b;r.lanes|=b;var F=Nh(r,f,b);ch(r,F);break a}}r=r.return}while(null!==r)}ci(c)}catch(qa){b=qa;G===c&&null!==c&&(G=c=c.return);continue}break}while(1)}function Yh(){var a=vd.current;vd.current= +jd;return null===a?jd:a}function sc(a,b){var c=n;n|=16;var d=Yh();R===a&&O===b||Gb(a,b);do try{Nj();break}catch(e){Zh(a,e)}while(1);ze();n=c;vd.current=d;if(null!==G)throw Error(m(261));R=null;O=0;return L}function Nj(){for(;null!==G;)di(G)}function Hj(){for(;null!==G&&!Oj();)di(G)}function di(a){var b=Pj(a.alternate,a,ta);a.memoizedProps=a.pendingProps;null===b?ci(a):G=b;kf.current=null}function ci(a){var b=a;do{var c=b.alternate;a=b.return;if(0===(b.flags&2048)){c=vj(c,b,ta);if(null!==c){G=c;return}c= +b;if(24!==c.tag&&23!==c.tag||null===c.memoizedState||0!==(ta&1073741824)||0===(c.mode&4)){for(var d=0,e=c.child;null!==e;)d|=e.lanes|e.childLanes,e=e.sibling;c.childLanes=d}null!==a&&0===(a.flags&2048)&&(null===a.firstEffect&&(a.firstEffect=b.firstEffect),null!==b.lastEffect&&(null!==a.lastEffect&&(a.lastEffect.nextEffect=b.firstEffect),a.lastEffect=b.lastEffect),1g&&(h=g,g=A,A=h),h=vg(p,A),f=vg(p,g),h&&f&&(1!==u.rangeCount||u.anchorNode!==h.node||u.anchorOffset!==h.offset||u.focusNode!==f.node||u.focusOffset!==f.offset)&&(q=q.createRange(),q.setStart(h.node,h.offset),u.removeAllRanges(),A>g?(u.addRange(q),u.extend(f.node, +f.offset)):(q.setEnd(f.node,f.offset),u.addRange(q))))));q=[];for(u=p;u=u.parentNode;)1===u.nodeType&&q.push({element:u,left:u.scrollLeft,top:u.scrollTop});"function"===typeof p.focus&&p.focus();for(p=0;pP()-df?Gb(a,0):jf|=c);ba(a,b)}function Ej(a,b){var c=a.stateNode;null!==c&&c.delete(b);b=0;0===b&&(b=a.mode,0===(b&2)?b=1:0===(b&4)?b=99===wb()?1:2:(0===ua&&(ua=Fb),b=nb(62914560&~ua),0===b&&(b=4194304))); +c=W();a=ud(a,b);null!==a&&(Oc(a,b,c),ba(a,c))}function Uj(a,b,c,d){this.tag=a;this.key=c;this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null;this.index=0;this.ref=null;this.pendingProps=b;this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null;this.mode=d;this.flags=0;this.lastEffect=this.firstEffect=this.nextEffect=null;this.childLanes=this.lanes=0;this.alternate=null}function Qe(a){a=a.prototype;return!(!a||!a.isReactComponent)}function Vj(a){if("function"=== +typeof a)return Qe(a)?1:0;if(void 0!==a&&null!==a){a=a.$$typeof;if(a===Dc)return 11;if(a===Ec)return 14}return 2}function Ma(a,b){var c=a.alternate;null===c?(c=Z(a.tag,b,a.key,a.mode),c.elementType=a.elementType,c.type=a.type,c.stateNode=a.stateNode,c.alternate=a,a.alternate=c):(c.pendingProps=b,c.type=a.type,c.flags=0,c.nextEffect=null,c.firstEffect=null,c.lastEffect=null);c.childLanes=a.childLanes;c.lanes=a.lanes;c.child=a.child;c.memoizedProps=a.memoizedProps;c.memoizedState=a.memoizedState;c.updateQueue= +a.updateQueue;b=a.dependencies;c.dependencies=null===b?null:{lanes:b.lanes,firstContext:b.firstContext};c.sibling=a.sibling;c.index=a.index;c.ref=a.ref;return c}function fd(a,b,c,d,e,f){var g=2;d=a;if("function"===typeof a)Qe(a)&&(g=1);else if("string"===typeof a)g=5;else a:switch(a){case wa:return zb(c.children,e,f,b);case fi:g=8;e|=16;break;case Hd:g=8;e|=1;break;case Lb:return a=Z(12,c,b,e|8),a.elementType=Lb,a.type=Lb,a.lanes=f,a;case Mb:return a=Z(13,c,b,e),a.type=Mb,a.elementType=Mb,a.lanes= +f,a;case Cc:return a=Z(19,c,b,e),a.elementType=Cc,a.lanes=f,a;case pf:return Ue(c,e,f,b);case qf:return a=Z(24,c,b,e),a.elementType=qf,a.lanes=f,a;default:if("object"===typeof a&&null!==a)switch(a.$$typeof){case Jd:g=10;break a;case Id:g=9;break a;case Dc:g=11;break a;case Ec:g=14;break a;case Ld:g=16;d=null;break a;case Kd:g=22;break a}throw Error(m(130,null==a?a:typeof a,""));}b=Z(g,c,b,e);b.elementType=a;b.type=d;b.lanes=f;return b}function zb(a,b,c,d){a=Z(7,a,d,b);a.lanes=c;return a}function Ue(a, +b,c,d){a=Z(23,a,d,b);a.elementType=pf;a.lanes=c;return a}function De(a,b,c){a=Z(6,a,null,b);a.lanes=c;return a}function Ee(a,b,c){b=Z(4,null!==a.children?a.children:[],a.key,b);b.lanes=c;b.stateNode={containerInfo:a.containerInfo,pendingChildren:null,implementation:a.implementation};return b}function Wj(a,b,c){this.tag=b;this.containerInfo=a;this.finishedWork=this.pingCache=this.current=this.pendingChildren=null;this.timeoutHandle=-1;this.pendingContext=this.context=null;this.hydrate=c;this.callbackNode= +null;this.callbackPriority=0;this.eventTimes=ge(0);this.expirationTimes=ge(-1);this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0;this.entanglements=ge(0);this.mutableSourceEagerHydrationData=null}function Xj(a,b,c){var d=3