From b1c5bfb230e86b6120caafc2fbb6273504bd0d42 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Tue, 6 Feb 2024 13:22:41 +0100 Subject: [PATCH 01/45] Update to wasmvm 2.0.0-rc.1 --- go.mod | 4 ++-- go.sum | 4 ++++ tests/e2e/gov_test.go | 2 +- tests/e2e/grants_test.go | 2 +- tests/e2e/reflect_helper.go | 2 +- x/wasm/client/cli/gov_tx.go | 2 +- x/wasm/client/cli/query.go | 2 +- x/wasm/ibc.go | 2 +- x/wasm/ibc_integration_test.go | 4 ++-- x/wasm/ibc_reflect_test.go | 2 +- x/wasm/ibc_test.go | 2 +- x/wasm/keeper/api.go | 4 ++-- x/wasm/keeper/events.go | 2 +- x/wasm/keeper/events_test.go | 2 +- x/wasm/keeper/genesis_test.go | 2 +- x/wasm/keeper/handler_plugin.go | 2 +- x/wasm/keeper/handler_plugin_encoders.go | 2 +- x/wasm/keeper/handler_plugin_encoders_test.go | 2 +- x/wasm/keeper/handler_plugin_test.go | 4 ++-- x/wasm/keeper/keeper.go | 4 ++-- x/wasm/keeper/keeper_cgo.go | 2 +- x/wasm/keeper/keeper_test.go | 4 ++-- x/wasm/keeper/metrics.go | 2 +- x/wasm/keeper/msg_dispatcher.go | 2 +- x/wasm/keeper/msg_dispatcher_test.go | 2 +- x/wasm/keeper/msg_server_integration_test.go | 4 ++-- x/wasm/keeper/options_test.go | 2 +- x/wasm/keeper/proposal_integration_test.go | 2 +- x/wasm/keeper/querier_test.go | 4 ++-- x/wasm/keeper/query_plugin_integration_test.go | 2 +- x/wasm/keeper/query_plugins.go | 2 +- x/wasm/keeper/query_plugins_test.go | 2 +- x/wasm/keeper/recurse_test.go | 2 +- x/wasm/keeper/reflect_test.go | 2 +- x/wasm/keeper/relay.go | 2 +- x/wasm/keeper/relay_test.go | 4 ++-- x/wasm/keeper/snapshotter_integration_test.go | 4 ++-- x/wasm/keeper/staking_test.go | 2 +- x/wasm/keeper/submsg_test.go | 4 ++-- x/wasm/keeper/testdata/contracts.go | 2 +- x/wasm/keeper/wasmtesting/gas_register.go | 2 +- x/wasm/keeper/wasmtesting/messenger.go | 2 +- x/wasm/keeper/wasmtesting/mock_engine.go | 4 ++-- x/wasm/keeper/wasmtesting/msg_dispatcher.go | 2 +- x/wasm/keeper/wasmtesting/query_handler.go | 2 +- x/wasm/module.go | 4 ++-- x/wasm/relay_pingpong_test.go | 4 ++-- x/wasm/relay_test.go | 4 ++-- x/wasm/simulation/operations.go | 2 +- x/wasm/types/authz.go | 2 +- x/wasm/types/authz_test.go | 2 +- x/wasm/types/errors.go | 2 +- x/wasm/types/errors_test.go | 2 +- x/wasm/types/exported_keepers.go | 2 +- x/wasm/types/gas_register.go | 2 +- x/wasm/types/gas_register_test.go | 2 +- x/wasm/types/test_fixtures.go | 2 +- x/wasm/types/types.go | 2 +- x/wasm/types/types_test.go | 2 +- x/wasm/types/wasmer_engine.go | 4 ++-- 60 files changed, 79 insertions(+), 75 deletions(-) diff --git a/go.mod b/go.mod index ac4486c9a4..a9f9b096e0 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/CosmWasm/wasmd go 1.21 require ( - github.com/CosmWasm/wasmvm v1.5.2 + github.com/CosmWasm/wasmvm/v2 v2.0.0-rc.1 github.com/cosmos/cosmos-proto v1.0.0-beta.3 github.com/cosmos/cosmos-sdk v0.50.1 github.com/cosmos/gogogateway v1.2.0 // indirect @@ -188,7 +188,7 @@ require ( golang.org/x/net v0.19.0 // indirect golang.org/x/oauth2 v0.13.0 // indirect golang.org/x/sync v0.5.0 // indirect - golang.org/x/sys v0.15.0 // indirect + golang.org/x/sys v0.16.0 // indirect golang.org/x/term v0.15.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect diff --git a/go.sum b/go.sum index 7b8b1890f7..91de6928bd 100644 --- a/go.sum +++ b/go.sum @@ -230,6 +230,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/CosmWasm/wasmvm v1.5.2 h1:+pKB1Mz9GZVt1vadxB+EDdD1FOz3dMNjIKq/58/lrag= github.com/CosmWasm/wasmvm v1.5.2/go.mod h1:Q0bSEtlktzh7W2hhEaifrFp1Erx11ckQZmjq8FLCyys= +github.com/CosmWasm/wasmvm/v2 v2.0.0-rc.1 h1:svmpiJLnLX8bQfqa4ZgsAIT/ldzPCjvJPNlHJkJhAlA= +github.com/CosmWasm/wasmvm/v2 v2.0.0-rc.1/go.mod h1:su9lg5qLr7adV95eOfzjZWkGiky8WNaNIHDr7Fpu7Ck= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ= github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= @@ -1342,6 +1344,8 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/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/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= diff --git a/tests/e2e/gov_test.go b/tests/e2e/gov_test.go index f57e6b1051..431abd9578 100644 --- a/tests/e2e/gov_test.go +++ b/tests/e2e/gov_test.go @@ -4,7 +4,7 @@ import ( "testing" "time" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/tests/e2e/grants_test.go b/tests/e2e/grants_test.go index 82748be8b2..203e23f0d3 100644 --- a/tests/e2e/grants_test.go +++ b/tests/e2e/grants_test.go @@ -6,7 +6,7 @@ import ( "testing" "time" - wasmvm "github.com/CosmWasm/wasmvm" + wasmvm "github.com/CosmWasm/wasmvm/v2" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/tests/e2e/reflect_helper.go b/tests/e2e/reflect_helper.go index 2d8a4c4d79..d715eefa2f 100644 --- a/tests/e2e/reflect_helper.go +++ b/tests/e2e/reflect_helper.go @@ -4,7 +4,7 @@ import ( "encoding/json" "testing" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" abci "github.com/cometbft/cometbft/abci/types" "github.com/cosmos/gogoproto/proto" "github.com/stretchr/testify/require" diff --git a/x/wasm/client/cli/gov_tx.go b/x/wasm/client/cli/gov_tx.go index ade701246d..9b95ae949d 100644 --- a/x/wasm/client/cli/gov_tx.go +++ b/x/wasm/client/cli/gov_tx.go @@ -7,7 +7,7 @@ import ( "strconv" "strings" - wasmvm "github.com/CosmWasm/wasmvm" + wasmvm "github.com/CosmWasm/wasmvm/v2" "github.com/distribution/reference" "github.com/pkg/errors" "github.com/spf13/cobra" diff --git a/x/wasm/client/cli/query.go b/x/wasm/client/cli/query.go index 9027c8050b..89f6790327 100644 --- a/x/wasm/client/cli/query.go +++ b/x/wasm/client/cli/query.go @@ -10,7 +10,7 @@ import ( "os" "strconv" - wasmvm "github.com/CosmWasm/wasmvm" + wasmvm "github.com/CosmWasm/wasmvm/v2" "github.com/spf13/cobra" flag "github.com/spf13/pflag" diff --git a/x/wasm/ibc.go b/x/wasm/ibc.go index b1a3e81a83..45adcf4d19 100644 --- a/x/wasm/ibc.go +++ b/x/wasm/ibc.go @@ -3,7 +3,7 @@ package wasm import ( "math" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" diff --git a/x/wasm/ibc_integration_test.go b/x/wasm/ibc_integration_test.go index eca8ca1ac1..cd45168274 100644 --- a/x/wasm/ibc_integration_test.go +++ b/x/wasm/ibc_integration_test.go @@ -4,8 +4,8 @@ import ( "encoding/json" "testing" - wasmvm "github.com/CosmWasm/wasmvm" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvm "github.com/CosmWasm/wasmvm/v2" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" ibctransfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" ibctesting "github.com/cosmos/ibc-go/v8/testing" diff --git a/x/wasm/ibc_reflect_test.go b/x/wasm/ibc_reflect_test.go index f0d3ced634..64de333ad5 100644 --- a/x/wasm/ibc_reflect_test.go +++ b/x/wasm/ibc_reflect_test.go @@ -3,7 +3,7 @@ package wasm_test import ( "testing" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" ibctesting "github.com/cosmos/ibc-go/v8/testing" "github.com/stretchr/testify/assert" diff --git a/x/wasm/ibc_test.go b/x/wasm/ibc_test.go index 271141e569..032c25f6e0 100644 --- a/x/wasm/ibc_test.go +++ b/x/wasm/ibc_test.go @@ -3,7 +3,7 @@ package wasm import ( "testing" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" abci "github.com/cometbft/cometbft/abci/types" "github.com/cometbft/cometbft/libs/rand" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" //nolint:staticcheck diff --git a/x/wasm/keeper/api.go b/x/wasm/keeper/api.go index 0a6f37c123..e9d5a00d48 100644 --- a/x/wasm/keeper/api.go +++ b/x/wasm/keeper/api.go @@ -1,8 +1,8 @@ package keeper import ( - wasmvm "github.com/CosmWasm/wasmvm" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvm "github.com/CosmWasm/wasmvm/v2" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/x/wasm/keeper/events.go b/x/wasm/keeper/events.go index b50719d461..0fc9d57400 100644 --- a/x/wasm/keeper/events.go +++ b/x/wasm/keeper/events.go @@ -4,7 +4,7 @@ import ( "fmt" "strings" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" errorsmod "cosmossdk.io/errors" diff --git a/x/wasm/keeper/events_test.go b/x/wasm/keeper/events_test.go index f3e5cc73f2..61182ad9c4 100644 --- a/x/wasm/keeper/events_test.go +++ b/x/wasm/keeper/events_test.go @@ -4,7 +4,7 @@ import ( "context" "testing" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" "github.com/stretchr/testify/assert" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/x/wasm/keeper/genesis_test.go b/x/wasm/keeper/genesis_test.go index b391ee0ba1..f16b151a4b 100644 --- a/x/wasm/keeper/genesis_test.go +++ b/x/wasm/keeper/genesis_test.go @@ -9,7 +9,7 @@ import ( "testing" "time" - wasmvm "github.com/CosmWasm/wasmvm" + wasmvm "github.com/CosmWasm/wasmvm/v2" abci "github.com/cometbft/cometbft/abci/types" cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" dbm "github.com/cosmos/cosmos-db" diff --git a/x/wasm/keeper/handler_plugin.go b/x/wasm/keeper/handler_plugin.go index 74dea048a7..9bfda34997 100644 --- a/x/wasm/keeper/handler_plugin.go +++ b/x/wasm/keeper/handler_plugin.go @@ -4,7 +4,7 @@ import ( "errors" "fmt" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" host "github.com/cosmos/ibc-go/v8/modules/core/24-host" diff --git a/x/wasm/keeper/handler_plugin_encoders.go b/x/wasm/keeper/handler_plugin_encoders.go index 9e783c98ca..d67969bd13 100644 --- a/x/wasm/keeper/handler_plugin_encoders.go +++ b/x/wasm/keeper/handler_plugin_encoders.go @@ -4,7 +4,7 @@ import ( "encoding/json" "fmt" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" ibctransfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" ibcclienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" //nolint:staticcheck channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" diff --git a/x/wasm/keeper/handler_plugin_encoders_test.go b/x/wasm/keeper/handler_plugin_encoders_test.go index 1374f03509..529f5028a0 100644 --- a/x/wasm/keeper/handler_plugin_encoders_test.go +++ b/x/wasm/keeper/handler_plugin_encoders_test.go @@ -3,7 +3,7 @@ package keeper import ( "testing" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" "github.com/cosmos/gogoproto/proto" ibctransfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" //nolint:staticcheck diff --git a/x/wasm/keeper/handler_plugin_test.go b/x/wasm/keeper/handler_plugin_test.go index 3a657a3ef1..b6f400f73c 100644 --- a/x/wasm/keeper/handler_plugin_test.go +++ b/x/wasm/keeper/handler_plugin_test.go @@ -4,8 +4,8 @@ import ( "encoding/json" "testing" - wasmvm "github.com/CosmWasm/wasmvm" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvm "github.com/CosmWasm/wasmvm/v2" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" //nolint:staticcheck channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" diff --git a/x/wasm/keeper/keeper.go b/x/wasm/keeper/keeper.go index f185d6e2a0..ccf16f677a 100644 --- a/x/wasm/keeper/keeper.go +++ b/x/wasm/keeper/keeper.go @@ -12,8 +12,8 @@ import ( "strings" "time" - wasmvm "github.com/CosmWasm/wasmvm" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvm "github.com/CosmWasm/wasmvm/v2" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" "cosmossdk.io/collections" corestoretypes "cosmossdk.io/core/store" diff --git a/x/wasm/keeper/keeper_cgo.go b/x/wasm/keeper/keeper_cgo.go index cb5baaa359..a2988fcc25 100644 --- a/x/wasm/keeper/keeper_cgo.go +++ b/x/wasm/keeper/keeper_cgo.go @@ -5,7 +5,7 @@ package keeper import ( "path/filepath" - wasmvm "github.com/CosmWasm/wasmvm" + wasmvm "github.com/CosmWasm/wasmvm/v2" "cosmossdk.io/collections" corestoretypes "cosmossdk.io/core/store" diff --git a/x/wasm/keeper/keeper_test.go b/x/wasm/keeper/keeper_test.go index d81ee793c4..ec943871bd 100644 --- a/x/wasm/keeper/keeper_test.go +++ b/x/wasm/keeper/keeper_test.go @@ -11,8 +11,8 @@ import ( "testing" "time" - wasmvm "github.com/CosmWasm/wasmvm" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvm "github.com/CosmWasm/wasmvm/v2" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" abci "github.com/cometbft/cometbft/abci/types" "github.com/cometbft/cometbft/libs/rand" tmproto "github.com/cometbft/cometbft/proto/tendermint/types" diff --git a/x/wasm/keeper/metrics.go b/x/wasm/keeper/metrics.go index 93f88581ca..37d7cd4300 100644 --- a/x/wasm/keeper/metrics.go +++ b/x/wasm/keeper/metrics.go @@ -1,7 +1,7 @@ package keeper import ( - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" "github.com/prometheus/client_golang/prometheus" ) diff --git a/x/wasm/keeper/msg_dispatcher.go b/x/wasm/keeper/msg_dispatcher.go index cbd66eed1f..5ab93e4520 100644 --- a/x/wasm/keeper/msg_dispatcher.go +++ b/x/wasm/keeper/msg_dispatcher.go @@ -5,7 +5,7 @@ import ( "sort" "strings" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" abci "github.com/cometbft/cometbft/abci/types" errorsmod "cosmossdk.io/errors" diff --git a/x/wasm/keeper/msg_dispatcher_test.go b/x/wasm/keeper/msg_dispatcher_test.go index 3cecfe6639..94fd46b871 100644 --- a/x/wasm/keeper/msg_dispatcher_test.go +++ b/x/wasm/keeper/msg_dispatcher_test.go @@ -5,7 +5,7 @@ import ( "fmt" "testing" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" abci "github.com/cometbft/cometbft/abci/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/x/wasm/keeper/msg_server_integration_test.go b/x/wasm/keeper/msg_server_integration_test.go index 5d737a93cc..06881bead0 100644 --- a/x/wasm/keeper/msg_server_integration_test.go +++ b/x/wasm/keeper/msg_server_integration_test.go @@ -6,8 +6,8 @@ import ( "testing" "time" - wasmvm "github.com/CosmWasm/wasmvm" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvm "github.com/CosmWasm/wasmvm/v2" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" tmproto "github.com/cometbft/cometbft/proto/tendermint/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/x/wasm/keeper/options_test.go b/x/wasm/keeper/options_test.go index ff3523a8c1..96ad46d205 100644 --- a/x/wasm/keeper/options_test.go +++ b/x/wasm/keeper/options_test.go @@ -4,7 +4,7 @@ import ( "reflect" "testing" - wasmvm "github.com/CosmWasm/wasmvm" + wasmvm "github.com/CosmWasm/wasmvm/v2" "github.com/prometheus/client_golang/prometheus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/x/wasm/keeper/proposal_integration_test.go b/x/wasm/keeper/proposal_integration_test.go index cb5256e462..b1cc8a38ea 100644 --- a/x/wasm/keeper/proposal_integration_test.go +++ b/x/wasm/keeper/proposal_integration_test.go @@ -6,7 +6,7 @@ import ( "fmt" "testing" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/x/wasm/keeper/querier_test.go b/x/wasm/keeper/querier_test.go index 2036095f0d..c81a32a449 100644 --- a/x/wasm/keeper/querier_test.go +++ b/x/wasm/keeper/querier_test.go @@ -9,8 +9,8 @@ import ( "testing" "time" - wasmvm "github.com/CosmWasm/wasmvm" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvm "github.com/CosmWasm/wasmvm/v2" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/grpc/codes" diff --git a/x/wasm/keeper/query_plugin_integration_test.go b/x/wasm/keeper/query_plugin_integration_test.go index 644c4ed093..5615e835f6 100644 --- a/x/wasm/keeper/query_plugin_integration_test.go +++ b/x/wasm/keeper/query_plugin_integration_test.go @@ -7,7 +7,7 @@ import ( "strings" "testing" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" "github.com/cosmos/gogoproto/proto" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" "github.com/stretchr/testify/assert" diff --git a/x/wasm/keeper/query_plugins.go b/x/wasm/keeper/query_plugins.go index 6e2cfa09b8..685dfc1b11 100644 --- a/x/wasm/keeper/query_plugins.go +++ b/x/wasm/keeper/query_plugins.go @@ -6,7 +6,7 @@ import ( "errors" "fmt" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" abci "github.com/cometbft/cometbft/abci/types" "github.com/cosmos/gogoproto/proto" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" diff --git a/x/wasm/keeper/query_plugins_test.go b/x/wasm/keeper/query_plugins_test.go index 57b0ddaef8..05559e7ee8 100644 --- a/x/wasm/keeper/query_plugins_test.go +++ b/x/wasm/keeper/query_plugins_test.go @@ -9,7 +9,7 @@ import ( "testing" "time" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" dbm "github.com/cosmos/cosmos-db" "github.com/cosmos/gogoproto/proto" diff --git a/x/wasm/keeper/recurse_test.go b/x/wasm/keeper/recurse_test.go index ebd7ef85f9..a0a2bae54a 100644 --- a/x/wasm/keeper/recurse_test.go +++ b/x/wasm/keeper/recurse_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "testing" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/x/wasm/keeper/reflect_test.go b/x/wasm/keeper/reflect_test.go index 95d9dff4a6..53bc35a980 100644 --- a/x/wasm/keeper/reflect_test.go +++ b/x/wasm/keeper/reflect_test.go @@ -5,7 +5,7 @@ import ( "os" "testing" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/x/wasm/keeper/relay.go b/x/wasm/keeper/relay.go index c542f6c04e..9f4c86e153 100644 --- a/x/wasm/keeper/relay.go +++ b/x/wasm/keeper/relay.go @@ -3,7 +3,7 @@ package keeper import ( "time" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported" diff --git a/x/wasm/keeper/relay_test.go b/x/wasm/keeper/relay_test.go index 4008fd7bfa..4c15816208 100644 --- a/x/wasm/keeper/relay_test.go +++ b/x/wasm/keeper/relay_test.go @@ -6,8 +6,8 @@ import ( "math" "testing" - wasmvm "github.com/CosmWasm/wasmvm" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvm "github.com/CosmWasm/wasmvm/v2" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/x/wasm/keeper/snapshotter_integration_test.go b/x/wasm/keeper/snapshotter_integration_test.go index 2262198597..eb216285c3 100644 --- a/x/wasm/keeper/snapshotter_integration_test.go +++ b/x/wasm/keeper/snapshotter_integration_test.go @@ -5,8 +5,8 @@ import ( "testing" "time" - wasmvm "github.com/CosmWasm/wasmvm" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvm "github.com/CosmWasm/wasmvm/v2" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" tmproto "github.com/cometbft/cometbft/proto/tendermint/types" tmtypes "github.com/cometbft/cometbft/types" "github.com/stretchr/testify/assert" diff --git a/x/wasm/keeper/staking_test.go b/x/wasm/keeper/staking_test.go index 6e1023d98f..292094a52e 100644 --- a/x/wasm/keeper/staking_test.go +++ b/x/wasm/keeper/staking_test.go @@ -5,7 +5,7 @@ import ( "os" "testing" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/x/wasm/keeper/submsg_test.go b/x/wasm/keeper/submsg_test.go index abb9088ead..9060ac6649 100644 --- a/x/wasm/keeper/submsg_test.go +++ b/x/wasm/keeper/submsg_test.go @@ -7,8 +7,8 @@ import ( "strconv" "testing" - wasmvm "github.com/CosmWasm/wasmvm" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvm "github.com/CosmWasm/wasmvm/v2" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/x/wasm/keeper/testdata/contracts.go b/x/wasm/keeper/testdata/contracts.go index 299fc9a324..fe587a091d 100644 --- a/x/wasm/keeper/testdata/contracts.go +++ b/x/wasm/keeper/testdata/contracts.go @@ -3,7 +3,7 @@ package testdata import ( _ "embed" - typwasmvmtypes "github.com/CosmWasm/wasmvm/types" + typwasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" "github.com/cosmos/cosmos-sdk/types" ) diff --git a/x/wasm/keeper/wasmtesting/gas_register.go b/x/wasm/keeper/wasmtesting/gas_register.go index fd7abe5491..9358b8a65c 100644 --- a/x/wasm/keeper/wasmtesting/gas_register.go +++ b/x/wasm/keeper/wasmtesting/gas_register.go @@ -1,7 +1,7 @@ package wasmtesting import ( - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" storetypes "cosmossdk.io/store/types" ) diff --git a/x/wasm/keeper/wasmtesting/messenger.go b/x/wasm/keeper/wasmtesting/messenger.go index 8f613cf667..3290580953 100644 --- a/x/wasm/keeper/wasmtesting/messenger.go +++ b/x/wasm/keeper/wasmtesting/messenger.go @@ -3,7 +3,7 @@ package wasmtesting import ( "errors" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" sdk "github.com/cosmos/cosmos-sdk/types" ) diff --git a/x/wasm/keeper/wasmtesting/mock_engine.go b/x/wasm/keeper/wasmtesting/mock_engine.go index b1c7b11d04..64fad36264 100644 --- a/x/wasm/keeper/wasmtesting/mock_engine.go +++ b/x/wasm/keeper/wasmtesting/mock_engine.go @@ -3,8 +3,8 @@ package wasmtesting import ( "bytes" - wasmvm "github.com/CosmWasm/wasmvm" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvm "github.com/CosmWasm/wasmvm/v2" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" "github.com/cometbft/cometbft/libs/rand" errorsmod "cosmossdk.io/errors" diff --git a/x/wasm/keeper/wasmtesting/msg_dispatcher.go b/x/wasm/keeper/wasmtesting/msg_dispatcher.go index 4d016f4741..2229fedab5 100644 --- a/x/wasm/keeper/wasmtesting/msg_dispatcher.go +++ b/x/wasm/keeper/wasmtesting/msg_dispatcher.go @@ -1,7 +1,7 @@ package wasmtesting import ( - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" sdk "github.com/cosmos/cosmos-sdk/types" ) diff --git a/x/wasm/keeper/wasmtesting/query_handler.go b/x/wasm/keeper/wasmtesting/query_handler.go index e70495b52f..5f4a4501bb 100644 --- a/x/wasm/keeper/wasmtesting/query_handler.go +++ b/x/wasm/keeper/wasmtesting/query_handler.go @@ -1,7 +1,7 @@ package wasmtesting import ( - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" sdk "github.com/cosmos/cosmos-sdk/types" ) diff --git a/x/wasm/module.go b/x/wasm/module.go index 8d5c8dc7f8..4fdf8f9dd4 100644 --- a/x/wasm/module.go +++ b/x/wasm/module.go @@ -7,7 +7,7 @@ import ( "runtime/debug" "strings" - wasmvm "github.com/CosmWasm/wasmvm" + wasmvm "github.com/CosmWasm/wasmvm/v2" abci "github.com/cometbft/cometbft/abci/types" "github.com/grpc-ecosystem/grpc-gateway/runtime" "github.com/spf13/cast" @@ -280,7 +280,7 @@ func getExpectedLibwasmVersion() string { panic("can't read build info") } for _, d := range buildInfo.Deps { - if d.Path != "github.com/CosmWasm/wasmvm" { + if d.Path != "github.com/CosmWasm/wasmvm/v2" { continue } if d.Replace != nil { diff --git a/x/wasm/relay_pingpong_test.go b/x/wasm/relay_pingpong_test.go index 2cf6a2634b..4fcf8926d5 100644 --- a/x/wasm/relay_pingpong_test.go +++ b/x/wasm/relay_pingpong_test.go @@ -5,8 +5,8 @@ import ( "fmt" "testing" - wasmvm "github.com/CosmWasm/wasmvm" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvm "github.com/CosmWasm/wasmvm/v2" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" ibctransfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" //nolint:staticcheck channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" diff --git a/x/wasm/relay_test.go b/x/wasm/relay_test.go index 91f1f34d72..e30b276bdc 100644 --- a/x/wasm/relay_test.go +++ b/x/wasm/relay_test.go @@ -6,8 +6,8 @@ import ( "testing" "time" - wasmvm "github.com/CosmWasm/wasmvm" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvm "github.com/CosmWasm/wasmvm/v2" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" ibctransfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" //nolint:staticcheck channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" diff --git a/x/wasm/simulation/operations.go b/x/wasm/simulation/operations.go index 845aa33963..c284a33342 100644 --- a/x/wasm/simulation/operations.go +++ b/x/wasm/simulation/operations.go @@ -6,7 +6,7 @@ import ( "math/rand" "os" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" errorsmod "cosmossdk.io/errors" diff --git a/x/wasm/types/authz.go b/x/wasm/types/authz.go index e0b4945961..0e8279703f 100644 --- a/x/wasm/types/authz.go +++ b/x/wasm/types/authz.go @@ -5,7 +5,7 @@ import ( "context" "strings" - wasmvm "github.com/CosmWasm/wasmvm" + wasmvm "github.com/CosmWasm/wasmvm/v2" "github.com/cosmos/gogoproto/proto" errorsmod "cosmossdk.io/errors" diff --git a/x/wasm/types/authz_test.go b/x/wasm/types/authz_test.go index 12ea9e07b5..f846691988 100644 --- a/x/wasm/types/authz_test.go +++ b/x/wasm/types/authz_test.go @@ -5,7 +5,7 @@ import ( "strings" "testing" - wasmvm "github.com/CosmWasm/wasmvm" + wasmvm "github.com/CosmWasm/wasmvm/v2" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/x/wasm/types/errors.go b/x/wasm/types/errors.go index 58aa5caf1a..027f001ac1 100644 --- a/x/wasm/types/errors.go +++ b/x/wasm/types/errors.go @@ -1,7 +1,7 @@ package types import ( - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" errorsmod "cosmossdk.io/errors" ) diff --git a/x/wasm/types/errors_test.go b/x/wasm/types/errors_test.go index 5e1034f628..d01578e7af 100644 --- a/x/wasm/types/errors_test.go +++ b/x/wasm/types/errors_test.go @@ -4,7 +4,7 @@ import ( "errors" "testing" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/x/wasm/types/exported_keepers.go b/x/wasm/types/exported_keepers.go index d00b39ce67..918ad214e3 100644 --- a/x/wasm/types/exported_keepers.go +++ b/x/wasm/types/exported_keepers.go @@ -3,7 +3,7 @@ package types import ( "context" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported" diff --git a/x/wasm/types/gas_register.go b/x/wasm/types/gas_register.go index 0011d64163..f77d3c854e 100644 --- a/x/wasm/types/gas_register.go +++ b/x/wasm/types/gas_register.go @@ -1,7 +1,7 @@ package types import ( - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" errorsmod "cosmossdk.io/errors" sdkmath "cosmossdk.io/math" diff --git a/x/wasm/types/gas_register_test.go b/x/wasm/types/gas_register_test.go index da7d123a9a..d8612ccfd7 100644 --- a/x/wasm/types/gas_register_test.go +++ b/x/wasm/types/gas_register_test.go @@ -5,7 +5,7 @@ import ( "strings" "testing" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" "github.com/stretchr/testify/assert" storetypes "cosmossdk.io/store/types" diff --git a/x/wasm/types/test_fixtures.go b/x/wasm/types/test_fixtures.go index f1e0164973..e1d03c59c7 100644 --- a/x/wasm/types/test_fixtures.go +++ b/x/wasm/types/test_fixtures.go @@ -4,7 +4,7 @@ import ( _ "embed" "math/rand" - wasmvm "github.com/CosmWasm/wasmvm" + wasmvm "github.com/CosmWasm/wasmvm/v2" sdkmath "cosmossdk.io/math" diff --git a/x/wasm/types/types.go b/x/wasm/types/types.go index fdf390cf86..e59ae1f8a3 100644 --- a/x/wasm/types/types.go +++ b/x/wasm/types/types.go @@ -4,7 +4,7 @@ import ( "fmt" "reflect" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" "github.com/cosmos/gogoproto/proto" errorsmod "cosmossdk.io/errors" diff --git a/x/wasm/types/types_test.go b/x/wasm/types/types_test.go index 0734937eef..d00cf5ca3a 100644 --- a/x/wasm/types/types_test.go +++ b/x/wasm/types/types_test.go @@ -7,7 +7,7 @@ import ( "testing" "time" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" "github.com/cometbft/cometbft/libs/rand" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/x/wasm/types/wasmer_engine.go b/x/wasm/types/wasmer_engine.go index e27715bf74..85f6b2408a 100644 --- a/x/wasm/types/wasmer_engine.go +++ b/x/wasm/types/wasmer_engine.go @@ -1,8 +1,8 @@ package types import ( - wasmvm "github.com/CosmWasm/wasmvm" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvm "github.com/CosmWasm/wasmvm/v2" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" storetypes "cosmossdk.io/store/types" ) From c7ba88f81d6391197e5da983cc1cfb7f2a282021 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Tue, 6 Feb 2024 14:12:21 +0100 Subject: [PATCH 02/45] Adjust to type changes and renamings --- app/app.go | 4 +-- tests/e2e/gov_test.go | 8 ++--- tests/e2e/reflect_helper.go | 2 +- x/wasm/ibc_reflect_test.go | 6 ++-- x/wasm/keeper/api.go | 8 ++--- x/wasm/keeper/events.go | 2 +- x/wasm/keeper/events_test.go | 30 +++++++++---------- x/wasm/keeper/handler_plugin_encoders.go | 20 ++++++------- x/wasm/keeper/handler_plugin_encoders_test.go | 16 +++++----- x/wasm/keeper/handler_plugin_test.go | 8 ++--- x/wasm/keeper/keeper.go | 2 +- x/wasm/keeper/keeper_cgo.go | 2 +- x/wasm/keeper/keeper_test.go | 10 ++++--- x/wasm/keeper/msg_dispatcher_test.go | 2 +- x/wasm/keeper/proposal_integration_test.go | 5 +++- x/wasm/keeper/query_plugins.go | 10 +++---- x/wasm/keeper/reflect_test.go | 4 +-- x/wasm/keeper/test_common.go | 6 ++-- x/wasm/keeper/wasmtesting/gas_register.go | 2 +- x/wasm/migrations/v1/store_test.go | 2 +- x/wasm/migrations/v3/store_test.go | 2 +- x/wasm/module_test.go | 2 +- x/wasm/relay_pingpong_test.go | 2 +- x/wasm/relay_test.go | 2 +- x/wasm/types/gas_register.go | 4 +-- x/wasm/types/gas_register_test.go | 2 +- x/wasm/types/types.go | 2 +- x/wasm/types/wasmer_engine.go | 14 +-------- 28 files changed, 85 insertions(+), 94 deletions(-) diff --git a/app/app.go b/app/app.go index 44934eae72..fa4789c926 100644 --- a/app/app.go +++ b/app/app.go @@ -7,7 +7,6 @@ import ( "os" "path/filepath" "sort" - "strings" "sync" abci "github.com/cometbft/cometbft/abci/types" @@ -629,7 +628,6 @@ func NewWasmApp( // The last arguments can contain custom message handlers, and custom query handlers, // if we want to allow any custom callbacks - availableCapabilities := strings.Join(AllCapabilities(), ",") app.WasmKeeper = wasmkeeper.NewKeeper( appCodec, runtime.NewKVStoreService(keys[wasmtypes.StoreKey]), @@ -646,7 +644,7 @@ func NewWasmApp( app.GRPCQueryRouter(), wasmDir, wasmConfig, - availableCapabilities, + AllCapabilities(), authtypes.NewModuleAddress(govtypes.ModuleName).String(), wasmOpts..., ) diff --git a/tests/e2e/gov_test.go b/tests/e2e/gov_test.go index 431abd9578..a0abd64edf 100644 --- a/tests/e2e/gov_test.go +++ b/tests/e2e/gov_test.go @@ -61,25 +61,25 @@ func TestGovVoteByContract(t *testing.T) { }{ "yes": { vote: &wasmvmtypes.VoteMsg{ - Vote: wasmvmtypes.Yes, + Option: wasmvmtypes.Yes, }, expPass: true, }, "no": { vote: &wasmvmtypes.VoteMsg{ - Vote: wasmvmtypes.No, + Option: wasmvmtypes.No, }, expPass: false, }, "abstain": { vote: &wasmvmtypes.VoteMsg{ - Vote: wasmvmtypes.Abstain, + Option: wasmvmtypes.Abstain, }, expPass: true, }, "no with veto": { vote: &wasmvmtypes.VoteMsg{ - Vote: wasmvmtypes.NoWithVeto, + Option: wasmvmtypes.NoWithVeto, }, expPass: false, }, diff --git a/tests/e2e/reflect_helper.go b/tests/e2e/reflect_helper.go index d715eefa2f..e64d8bf139 100644 --- a/tests/e2e/reflect_helper.go +++ b/tests/e2e/reflect_helper.go @@ -42,7 +42,7 @@ func MustExecViaStargateReflectContract[T sdkMessageType](t *testing.T, chain *i bz, err := chain.Codec.Marshal(m) require.NoError(t, err) vmMsgs[i] = wasmvmtypes.CosmosMsg{ - Stargate: &wasmvmtypes.StargateMsg{ + Any: &wasmvmtypes.AnyMsg{ TypeURL: sdk.MsgTypeURL(m), Value: bz, }, diff --git a/x/wasm/ibc_reflect_test.go b/x/wasm/ibc_reflect_test.go index 64de333ad5..2d847f8f1a 100644 --- a/x/wasm/ibc_reflect_test.go +++ b/x/wasm/ibc_reflect_test.go @@ -116,7 +116,7 @@ type AccountQuery struct { } type AccountResponse struct { - LastUpdateTime uint64 `json:"last_update_time,string"` - RemoteAddr string `json:"remote_addr"` - RemoteBalance wasmvmtypes.Coins `json:"remote_balance"` + LastUpdateTime uint64 `json:"last_update_time,string"` + RemoteAddr string `json:"remote_addr"` + RemoteBalance wasmvmtypes.Array[wasmvmtypes.Coin] `json:"remote_balance"` } diff --git a/x/wasm/keeper/api.go b/x/wasm/keeper/api.go index e9d5a00d48..8101fef246 100644 --- a/x/wasm/keeper/api.go +++ b/x/wasm/keeper/api.go @@ -28,19 +28,19 @@ var ( } ) -func humanAddress(canon []byte) (string, uint64, error) { +func humanizeAddress(canon []byte) (string, uint64, error) { if err := sdk.VerifyAddressFormat(canon); err != nil { return "", costHumanize, err } return sdk.AccAddress(canon).String(), costHumanize, nil } -func canonicalAddress(human string) ([]byte, uint64, error) { +func canonicalizeAddress(human string) ([]byte, uint64, error) { bz, err := sdk.AccAddressFromBech32(human) return bz, costCanonical, err } var cosmwasmAPI = wasmvm.GoAPI{ - HumanAddress: humanAddress, - CanonicalAddress: canonicalAddress, + HumanizeAddress: humanizeAddress, + CanonicalizeAddress: canonicalizeAddress, } diff --git a/x/wasm/keeper/events.go b/x/wasm/keeper/events.go index 0fc9d57400..5cfb075b2e 100644 --- a/x/wasm/keeper/events.go +++ b/x/wasm/keeper/events.go @@ -28,7 +28,7 @@ func newWasmModuleEvent(customAttributes []wasmvmtypes.EventAttribute, contractA const eventTypeMinLength = 2 // newCustomEvents converts wasmvm events from a contract response to sdk type events -func newCustomEvents(evts wasmvmtypes.Events, contractAddr sdk.AccAddress) (sdk.Events, error) { +func newCustomEvents(evts wasmvmtypes.Array[wasmvmtypes.Event], contractAddr sdk.AccAddress) (sdk.Events, error) { events := make(sdk.Events, 0, len(evts)) for _, e := range evts { typ := strings.TrimSpace(e.Type) diff --git a/x/wasm/keeper/events_test.go b/x/wasm/keeper/events_test.go index 61182ad9c4..6516703ec5 100644 --- a/x/wasm/keeper/events_test.go +++ b/x/wasm/keeper/events_test.go @@ -56,12 +56,12 @@ func TestHasWasmModuleEvent(t *testing.T) { func TestNewCustomEvents(t *testing.T) { myContract := RandomAccountAddress(t) specs := map[string]struct { - src wasmvmtypes.Events + src wasmvmtypes.Array[wasmvmtypes.Event] exp sdk.Events isError bool }{ "all good": { - src: wasmvmtypes.Events{{ + src: wasmvmtypes.Array[wasmvmtypes.Event]{{ Type: "foo", Attributes: []wasmvmtypes.EventAttribute{{Key: "myKey", Value: "myVal"}}, }}, @@ -70,7 +70,7 @@ func TestNewCustomEvents(t *testing.T) { sdk.NewAttribute("myKey", "myVal"))}, }, "multiple attributes": { - src: wasmvmtypes.Events{{ + src: wasmvmtypes.Array[wasmvmtypes.Event]{{ Type: "foo", Attributes: []wasmvmtypes.EventAttribute{ {Key: "myKey", Value: "myVal"}, @@ -83,7 +83,7 @@ func TestNewCustomEvents(t *testing.T) { sdk.NewAttribute("myOtherKey", "myOtherVal"))}, }, "multiple events": { - src: wasmvmtypes.Events{{ + src: wasmvmtypes.Array[wasmvmtypes.Event]{{ Type: "foo", Attributes: []wasmvmtypes.EventAttribute{{Key: "myKey", Value: "myVal"}}, }, { @@ -100,14 +100,14 @@ func TestNewCustomEvents(t *testing.T) { }, }, "without attributes": { - src: wasmvmtypes.Events{{ + src: wasmvmtypes.Array[wasmvmtypes.Event]{{ Type: "foo", }}, exp: sdk.Events{sdk.NewEvent("wasm-foo", sdk.NewAttribute("_contract_address", myContract.String()))}, }, "empty value can be solved": { - src: wasmvmtypes.Events{{ + src: wasmvmtypes.Array[wasmvmtypes.Event]{{ Type: "foo", Attributes: []wasmvmtypes.EventAttribute{{Key: "myKey", Value: ""}}, }}, @@ -116,7 +116,7 @@ func TestNewCustomEvents(t *testing.T) { sdk.NewAttribute("myKey", ""))}, }, "good on whitespace value": { - src: wasmvmtypes.Events{{ + src: wasmvmtypes.Array[wasmvmtypes.Event]{{ Type: "foo", Attributes: []wasmvmtypes.EventAttribute{{Key: "myKey", Value: "\n\n\n"}}, }}, exp: sdk.Events{sdk.NewEvent("wasm-foo", @@ -124,20 +124,20 @@ func TestNewCustomEvents(t *testing.T) { sdk.NewAttribute("myKey", ""))}, }, "error on short event type": { - src: wasmvmtypes.Events{{ + src: wasmvmtypes.Array[wasmvmtypes.Event]{{ Type: "f", }}, isError: true, }, "error on _contract_address": { - src: wasmvmtypes.Events{{ + src: wasmvmtypes.Array[wasmvmtypes.Event]{{ Type: "foo", Attributes: []wasmvmtypes.EventAttribute{{Key: "_contract_address", Value: RandomBech32AccountAddress(t)}}, }}, isError: true, }, "error on reserved prefix": { - src: wasmvmtypes.Events{{ + src: wasmvmtypes.Array[wasmvmtypes.Event]{{ Type: "wasm", Attributes: []wasmvmtypes.EventAttribute{ {Key: "_reserved", Value: "is skipped"}, @@ -147,7 +147,7 @@ func TestNewCustomEvents(t *testing.T) { isError: true, }, "error on empty key": { - src: wasmvmtypes.Events{{ + src: wasmvmtypes.Array[wasmvmtypes.Event]{{ Type: "boom", Attributes: []wasmvmtypes.EventAttribute{ {Key: "some", Value: "data"}, @@ -157,7 +157,7 @@ func TestNewCustomEvents(t *testing.T) { isError: true, }, "error on whitespace type": { - src: wasmvmtypes.Events{{ + src: wasmvmtypes.Array[wasmvmtypes.Event]{{ Type: " f ", Attributes: []wasmvmtypes.EventAttribute{ {Key: "some", Value: "data"}, @@ -166,7 +166,7 @@ func TestNewCustomEvents(t *testing.T) { isError: true, }, "error on only whitespace key": { - src: wasmvmtypes.Events{{ + src: wasmvmtypes.Array[wasmvmtypes.Event]{{ Type: "boom", Attributes: []wasmvmtypes.EventAttribute{ {Key: "some", Value: "data"}, @@ -176,7 +176,7 @@ func TestNewCustomEvents(t *testing.T) { isError: true, }, "strip out whitespace": { - src: wasmvmtypes.Events{{ + src: wasmvmtypes.Array[wasmvmtypes.Event]{{ Type: " food\n", Attributes: []wasmvmtypes.EventAttribute{{Key: "my Key", Value: "\tmyVal"}}, }}, @@ -185,7 +185,7 @@ func TestNewCustomEvents(t *testing.T) { sdk.NewAttribute("my Key", "myVal"))}, }, "empty event elements": { - src: make(wasmvmtypes.Events, 10), + src: make(wasmvmtypes.Array[wasmvmtypes.Event], 10), isError: true, }, "nil": { diff --git a/x/wasm/keeper/handler_plugin_encoders.go b/x/wasm/keeper/handler_plugin_encoders.go index d67969bd13..91c56580e7 100644 --- a/x/wasm/keeper/handler_plugin_encoders.go +++ b/x/wasm/keeper/handler_plugin_encoders.go @@ -28,7 +28,7 @@ type ( CustomEncoder func(sender sdk.AccAddress, msg json.RawMessage) ([]sdk.Msg, error) DistributionEncoder func(sender sdk.AccAddress, msg *wasmvmtypes.DistributionMsg) ([]sdk.Msg, error) StakingEncoder func(sender sdk.AccAddress, msg *wasmvmtypes.StakingMsg) ([]sdk.Msg, error) - StargateEncoder func(sender sdk.AccAddress, msg *wasmvmtypes.StargateMsg) ([]sdk.Msg, error) + AnyEncoder func(sender sdk.AccAddress, msg *wasmvmtypes.AnyMsg) ([]sdk.Msg, error) WasmEncoder func(sender sdk.AccAddress, msg *wasmvmtypes.WasmMsg) ([]sdk.Msg, error) IBCEncoder func(ctx sdk.Context, sender sdk.AccAddress, contractIBCPortID string, msg *wasmvmtypes.IBCMsg) ([]sdk.Msg, error) ) @@ -39,7 +39,7 @@ type MessageEncoders struct { Distribution func(sender sdk.AccAddress, msg *wasmvmtypes.DistributionMsg) ([]sdk.Msg, error) IBC func(ctx sdk.Context, sender sdk.AccAddress, contractIBCPortID string, msg *wasmvmtypes.IBCMsg) ([]sdk.Msg, error) Staking func(sender sdk.AccAddress, msg *wasmvmtypes.StakingMsg) ([]sdk.Msg, error) - Stargate func(sender sdk.AccAddress, msg *wasmvmtypes.StargateMsg) ([]sdk.Msg, error) + Any func(sender sdk.AccAddress, msg *wasmvmtypes.AnyMsg) ([]sdk.Msg, error) Wasm func(sender sdk.AccAddress, msg *wasmvmtypes.WasmMsg) ([]sdk.Msg, error) Gov func(sender sdk.AccAddress, msg *wasmvmtypes.GovMsg) ([]sdk.Msg, error) } @@ -51,7 +51,7 @@ func DefaultEncoders(unpacker codectypes.AnyUnpacker, portSource types.ICS20Tran Distribution: EncodeDistributionMsg, IBC: EncodeIBCMsg(portSource), Staking: EncodeStakingMsg, - Stargate: EncodeStargateMsg(unpacker), + Any: EncodeAnyMsg(unpacker), Wasm: EncodeWasmMsg, Gov: EncodeGovMsg, } @@ -76,8 +76,8 @@ func (e MessageEncoders) Merge(o *MessageEncoders) MessageEncoders { if o.Staking != nil { e.Staking = o.Staking } - if o.Stargate != nil { - e.Stargate = o.Stargate + if o.Any != nil { + e.Any = o.Any } if o.Wasm != nil { e.Wasm = o.Wasm @@ -100,8 +100,8 @@ func (e MessageEncoders) Encode(ctx sdk.Context, contractAddr sdk.AccAddress, co return e.IBC(ctx, contractAddr, contractIBCPortID, msg.IBC) case msg.Staking != nil: return e.Staking(contractAddr, msg.Staking) - case msg.Stargate != nil: - return e.Stargate(contractAddr, msg.Stargate) + case msg.Any != nil: + return e.Any(contractAddr, msg.Any) case msg.Wasm != nil: return e.Wasm(contractAddr, msg.Wasm) case msg.Gov != nil: @@ -204,8 +204,8 @@ func EncodeStakingMsg(sender sdk.AccAddress, msg *wasmvmtypes.StakingMsg) ([]sdk } } -func EncodeStargateMsg(unpacker codectypes.AnyUnpacker) StargateEncoder { - return func(sender sdk.AccAddress, msg *wasmvmtypes.StargateMsg) ([]sdk.Msg, error) { +func EncodeAnyMsg(unpacker codectypes.AnyUnpacker) AnyEncoder { + return func(sender sdk.AccAddress, msg *wasmvmtypes.AnyMsg) ([]sdk.Msg, error) { codecAny := codectypes.Any{ TypeUrl: msg.TypeURL, Value: msg.Value, @@ -328,7 +328,7 @@ func EncodeIBCMsg(portSource types.ICS20TransferPortSource) func(ctx sdk.Context func EncodeGovMsg(sender sdk.AccAddress, msg *wasmvmtypes.GovMsg) ([]sdk.Msg, error) { switch { case msg.Vote != nil: - voteOption, err := convertVoteOption(msg.Vote.Vote) + voteOption, err := convertVoteOption(msg.Vote.Option) if err != nil { return nil, errorsmod.Wrap(err, "vote option") } diff --git a/x/wasm/keeper/handler_plugin_encoders_test.go b/x/wasm/keeper/handler_plugin_encoders_test.go index 529f5028a0..9d29947b54 100644 --- a/x/wasm/keeper/handler_plugin_encoders_test.go +++ b/x/wasm/keeper/handler_plugin_encoders_test.go @@ -381,7 +381,7 @@ func TestEncoding(t *testing.T) { srcMsg: wasmvmtypes.CosmosMsg{ Distribution: &wasmvmtypes.DistributionMsg{ FundCommunityPool: &wasmvmtypes.FundCommunityPoolMsg{ - Amount: wasmvmtypes.Coins{ + Amount: wasmvmtypes.Array[wasmvmtypes.Coin]{ wasmvmtypes.NewCoin(200, "stones"), wasmvmtypes.NewCoin(200, "feathers"), }, @@ -401,7 +401,7 @@ func TestEncoding(t *testing.T) { "stargate encoded bank msg": { sender: addr2, srcMsg: wasmvmtypes.CosmosMsg{ - Stargate: &wasmvmtypes.StargateMsg{ + Any: &wasmvmtypes.AnyMsg{ TypeURL: "/cosmos.bank.v1beta1.MsgSend", Value: bankMsgBin, }, @@ -411,7 +411,7 @@ func TestEncoding(t *testing.T) { "stargate encoded msg with any type": { sender: addr2, srcMsg: wasmvmtypes.CosmosMsg{ - Stargate: &wasmvmtypes.StargateMsg{ + Any: &wasmvmtypes.AnyMsg{ TypeURL: "/cosmos.gov.v1.MsgSubmitProposal", Value: proposalMsgBin, }, @@ -421,7 +421,7 @@ func TestEncoding(t *testing.T) { "stargate encoded invalid typeUrl": { sender: addr2, srcMsg: wasmvmtypes.CosmosMsg{ - Stargate: &wasmvmtypes.StargateMsg{ + Any: &wasmvmtypes.AnyMsg{ TypeURL: "/cosmos.bank.v2.MsgSend", Value: bankMsgBin, }, @@ -581,7 +581,7 @@ func TestEncodeGovMsg(t *testing.T) { sender: myAddr, srcMsg: wasmvmtypes.CosmosMsg{ Gov: &wasmvmtypes.GovMsg{ - Vote: &wasmvmtypes.VoteMsg{ProposalId: 1, Vote: wasmvmtypes.Yes}, + Vote: &wasmvmtypes.VoteMsg{ProposalId: 1, Option: wasmvmtypes.Yes}, }, }, output: []sdk.Msg{ @@ -596,7 +596,7 @@ func TestEncodeGovMsg(t *testing.T) { sender: myAddr, srcMsg: wasmvmtypes.CosmosMsg{ Gov: &wasmvmtypes.GovMsg{ - Vote: &wasmvmtypes.VoteMsg{ProposalId: 1, Vote: wasmvmtypes.No}, + Vote: &wasmvmtypes.VoteMsg{ProposalId: 1, Option: wasmvmtypes.No}, }, }, output: []sdk.Msg{ @@ -611,7 +611,7 @@ func TestEncodeGovMsg(t *testing.T) { sender: myAddr, srcMsg: wasmvmtypes.CosmosMsg{ Gov: &wasmvmtypes.GovMsg{ - Vote: &wasmvmtypes.VoteMsg{ProposalId: 10, Vote: wasmvmtypes.Abstain}, + Vote: &wasmvmtypes.VoteMsg{ProposalId: 10, Option: wasmvmtypes.Abstain}, }, }, output: []sdk.Msg{ @@ -626,7 +626,7 @@ func TestEncodeGovMsg(t *testing.T) { sender: myAddr, srcMsg: wasmvmtypes.CosmosMsg{ Gov: &wasmvmtypes.GovMsg{ - Vote: &wasmvmtypes.VoteMsg{ProposalId: 1, Vote: wasmvmtypes.NoWithVeto}, + Vote: &wasmvmtypes.VoteMsg{ProposalId: 1, Option: wasmvmtypes.NoWithVeto}, }, }, output: []sdk.Msg{ diff --git a/x/wasm/keeper/handler_plugin_test.go b/x/wasm/keeper/handler_plugin_test.go index b6f400f73c..b86c86fd7f 100644 --- a/x/wasm/keeper/handler_plugin_test.go +++ b/x/wasm/keeper/handler_plugin_test.go @@ -350,7 +350,7 @@ func TestBurnCoinMessageHandlerIntegration(t *testing.T) { }{ "all good": { msg: wasmvmtypes.BurnMsg{ - Amount: wasmvmtypes.Coins{{ + Amount: wasmvmtypes.Array[wasmvmtypes.Coin]{{ Denom: "denom", Amount: "100", }}, @@ -358,7 +358,7 @@ func TestBurnCoinMessageHandlerIntegration(t *testing.T) { }, "not enough funds in contract": { msg: wasmvmtypes.BurnMsg{ - Amount: wasmvmtypes.Coins{{ + Amount: wasmvmtypes.Array[wasmvmtypes.Coin]{{ Denom: "denom", Amount: "101", }}, @@ -367,7 +367,7 @@ func TestBurnCoinMessageHandlerIntegration(t *testing.T) { }, "zero amount rejected": { msg: wasmvmtypes.BurnMsg{ - Amount: wasmvmtypes.Coins{{ + Amount: wasmvmtypes.Array[wasmvmtypes.Coin]{{ Denom: "denom", Amount: "0", }}, @@ -376,7 +376,7 @@ func TestBurnCoinMessageHandlerIntegration(t *testing.T) { }, "unknown denom - insufficient funds": { msg: wasmvmtypes.BurnMsg{ - Amount: wasmvmtypes.Coins{{ + Amount: wasmvmtypes.Array[wasmvmtypes.Coin]{{ Denom: "unknown", Amount: "1", }}, diff --git a/x/wasm/keeper/keeper.go b/x/wasm/keeper/keeper.go index ccf16f677a..1e47aa66c6 100644 --- a/x/wasm/keeper/keeper.go +++ b/x/wasm/keeper/keeper.go @@ -1075,7 +1075,7 @@ func (k *Keeper) handleContractResponse( msgs []wasmvmtypes.SubMsg, attrs []wasmvmtypes.EventAttribute, data []byte, - evts wasmvmtypes.Events, + evts wasmvmtypes.Array[wasmvmtypes.Event], ) ([]byte, error) { attributeGasCost := k.gasRegister.EventCosts(attrs, evts) ctx.GasMeter().ConsumeGas(attributeGasCost, "Custom contract event attributes") diff --git a/x/wasm/keeper/keeper_cgo.go b/x/wasm/keeper/keeper_cgo.go index a2988fcc25..020fef834d 100644 --- a/x/wasm/keeper/keeper_cgo.go +++ b/x/wasm/keeper/keeper_cgo.go @@ -33,7 +33,7 @@ func NewKeeper( _ GRPCQueryRouter, homeDir string, wasmConfig types.WasmConfig, - availableCapabilities string, + availableCapabilities []string, authority string, opts ...Option, ) Keeper { diff --git a/x/wasm/keeper/keeper_test.go b/x/wasm/keeper/keeper_test.go index ec943871bd..fefed2726a 100644 --- a/x/wasm/keeper/keeper_test.go +++ b/x/wasm/keeper/keeper_test.go @@ -43,7 +43,9 @@ import ( //go:embed testdata/hackatom.wasm var hackatomWasm []byte -const AvailableCapabilities = "iterator,staking,stargate,cosmwasm_1_1,cosmwasm_1_2,cosmwasm_1_3,cosmwasm_1_4" +var AvailableCapabilities = []string{ + "iterator", "staking", "stargate", "cosmwasm_1_1", "cosmwasm_1_2", "cosmwasm_1_3", "cosmwasm_1_4", +} func TestNewKeeper(t *testing.T) { _, keepers := CreateTestInput(t, false, AvailableCapabilities) @@ -1510,8 +1512,8 @@ type sudoMsg struct { } type stealFundsMsg struct { - Recipient string `json:"recipient"` - Amount wasmvmtypes.Coins `json:"amount"` + Recipient string `json:"recipient"` + Amount wasmvmtypes.Array[wasmvmtypes.Coin] `json:"amount"` } func TestSudo(t *testing.T) { @@ -1549,7 +1551,7 @@ func TestSudo(t *testing.T) { // to end users (via Tx/Execute). StealFunds: stealFundsMsg{ Recipient: community.String(), - Amount: wasmvmtypes.Coins{wasmvmtypes.NewCoin(76543, "denom")}, + Amount: wasmvmtypes.Array[wasmvmtypes.Coin]{wasmvmtypes.NewCoin(76543, "denom")}, }, } sudoMsg, err := json.Marshal(msg) diff --git a/x/wasm/keeper/msg_dispatcher_test.go b/x/wasm/keeper/msg_dispatcher_test.go index 94fd46b871..d9b0a9d6e8 100644 --- a/x/wasm/keeper/msg_dispatcher_test.go +++ b/x/wasm/keeper/msg_dispatcher_test.go @@ -348,7 +348,7 @@ func TestDispatchSubmessages(t *testing.T) { }, "non-wasm reply events get filtered": { // show events from a stargate message gets filtered out - msgs: []wasmvmtypes.SubMsg{{ID: 1, ReplyOn: wasmvmtypes.ReplyAlways, Msg: wasmvmtypes.CosmosMsg{Stargate: &wasmvmtypes.StargateMsg{}}}}, + msgs: []wasmvmtypes.SubMsg{{ID: 1, ReplyOn: wasmvmtypes.ReplyAlways, Msg: wasmvmtypes.CosmosMsg{Any: &wasmvmtypes.AnyMsg{}}}}, replyer: &mockReplyer{ replyFn: func(ctx sdk.Context, contractAddress sdk.AccAddress, reply wasmvmtypes.Reply) ([]byte, error) { if reply.Result.Err != "" { diff --git a/x/wasm/keeper/proposal_integration_test.go b/x/wasm/keeper/proposal_integration_test.go index b1cc8a38ea..c228424180 100644 --- a/x/wasm/keeper/proposal_integration_test.go +++ b/x/wasm/keeper/proposal_integration_test.go @@ -23,7 +23,10 @@ import ( ) func TestLoadStoredGovV1Beta1LegacyTypes(t *testing.T) { - pCtx, keepers := CreateTestInput(t, false, ReflectCapabilities+",iterator") + capabilities := make([]string, len(ReflectCapabilities)+1) + copy(capabilities, ReflectCapabilities) + capabilities = append(capabilities, "iterator") + pCtx, keepers := CreateTestInput(t, false, capabilities) k := keepers.WasmKeeper keepers.GovKeeper.SetLegacyRouter(v1beta1.NewRouter(). AddRoute(types.ModuleName, NewLegacyWasmProposalHandler(k, types.EnableAllProposals)), diff --git a/x/wasm/keeper/query_plugins.go b/x/wasm/keeper/query_plugins.go index 685dfc1b11..488e4d3adb 100644 --- a/x/wasm/keeper/query_plugins.go +++ b/x/wasm/keeper/query_plugins.go @@ -255,10 +255,10 @@ func IBCQuerier(wasm contractMetaDataSource, channelKeeper types.ChannelKeeper) if portID == "" { // then fallback to contract port address portID = wasm.GetContractInfo(ctx, caller).IBCPortID } - var channels wasmvmtypes.IBCChannels + var channels wasmvmtypes.Array[wasmvmtypes.IBCChannel] if portID != "" { // then return empty list for non ibc contracts; no channels possible gotChannels := channelKeeper.GetAllChannelsWithPortPrefix(ctx, portID) - channels = make(wasmvmtypes.IBCChannels, 0, len(gotChannels)) + channels = make(wasmvmtypes.Array[wasmvmtypes.IBCChannel], 0, len(gotChannels)) for _, ch := range gotChannels { if ch.State != channeltypes.OPEN { continue @@ -461,7 +461,7 @@ func StakingQuerier(keeper types.StakingKeeper, distKeeper types.DistributionKee } } -func sdkToDelegations(ctx sdk.Context, keeper types.StakingKeeper, delegations []stakingtypes.Delegation) (wasmvmtypes.Delegations, error) { +func sdkToDelegations(ctx sdk.Context, keeper types.StakingKeeper, delegations []stakingtypes.Delegation) (wasmvmtypes.Array[wasmvmtypes.Delegation], error) { result := make([]wasmvmtypes.Delegation, len(delegations)) bondDenom, err := keeper.BondDenom(ctx) if err != nil { @@ -706,8 +706,8 @@ func ConvertSDKDecCoinsToWasmDecCoins(src sdk.DecCoins) []wasmvmtypes.DecCoin { } // ConvertSdkCoinsToWasmCoins covert sdk type to wasmvm coins type -func ConvertSdkCoinsToWasmCoins(coins []sdk.Coin) wasmvmtypes.Coins { - converted := make(wasmvmtypes.Coins, len(coins)) +func ConvertSdkCoinsToWasmCoins(coins []sdk.Coin) wasmvmtypes.Array[wasmvmtypes.Coin] { + converted := make(wasmvmtypes.Array[wasmvmtypes.Coin], len(coins)) for i, c := range coins { converted[i] = ConvertSdkCoinToWasmCoin(c) } diff --git a/x/wasm/keeper/reflect_test.go b/x/wasm/keeper/reflect_test.go index 53bc35a980..24581f2806 100644 --- a/x/wasm/keeper/reflect_test.go +++ b/x/wasm/keeper/reflect_test.go @@ -23,8 +23,8 @@ import ( "github.com/CosmWasm/wasmd/x/wasm/types" ) -const ( - CyberpunkCapabilities = "staking,mask,stargate,cosmwasm_1_1,cosmwasm_1_2,cosmwasm_1_3,cosmwasm_1_4" +var ( + CyberpunkCapabilities = []string{"staking", "mask", "stargate", "cosmwasm_1_1", "cosmwasm_1_2", "cosmwasm_1_3", "cosmwasm_1_4"} ReflectCapabilities = CyberpunkCapabilities ) diff --git a/x/wasm/keeper/test_common.go b/x/wasm/keeper/test_common.go index a6809702ac..15a6aa8942 100644 --- a/x/wasm/keeper/test_common.go +++ b/x/wasm/keeper/test_common.go @@ -197,11 +197,11 @@ type TestKeepers struct { // CreateDefaultTestInput common settings for CreateTestInput func CreateDefaultTestInput(t testing.TB) (sdk.Context, TestKeepers) { - return CreateTestInput(t, false, "staking") + return CreateTestInput(t, false, []string{"staking"}) } // CreateTestInput encoders can be nil to accept the defaults, or set it to override some of the message handlers (like default) -func CreateTestInput(t testing.TB, isCheckTx bool, availableCapabilities string, opts ...Option) (sdk.Context, TestKeepers) { +func CreateTestInput(t testing.TB, isCheckTx bool, availableCapabilities []string, opts ...Option) (sdk.Context, TestKeepers) { // Load default wasm config return createTestInput(t, isCheckTx, availableCapabilities, types.DefaultWasmConfig(), dbm.NewMemDB(), opts...) } @@ -210,7 +210,7 @@ func CreateTestInput(t testing.TB, isCheckTx bool, availableCapabilities string, func createTestInput( t testing.TB, isCheckTx bool, - availableCapabilities string, + availableCapabilities []string, wasmConfig types.WasmConfig, db dbm.DB, opts ...Option, diff --git a/x/wasm/keeper/wasmtesting/gas_register.go b/x/wasm/keeper/wasmtesting/gas_register.go index 9358b8a65c..77c176e4ea 100644 --- a/x/wasm/keeper/wasmtesting/gas_register.go +++ b/x/wasm/keeper/wasmtesting/gas_register.go @@ -45,7 +45,7 @@ func (m MockGasRegister) ReplyCosts(discount bool, reply wasmvmtypes.Reply) stor return m.ReplyCostFn(discount, reply) } -func (m MockGasRegister) EventCosts(evts []wasmvmtypes.EventAttribute, _ wasmvmtypes.Events) storetypes.Gas { +func (m MockGasRegister) EventCosts(evts []wasmvmtypes.EventAttribute, _ wasmvmtypes.Array[wasmvmtypes.Event]) storetypes.Gas { if m.EventCostsFn == nil { panic("not expected to be called") } diff --git a/x/wasm/migrations/v1/store_test.go b/x/wasm/migrations/v1/store_test.go index 7afec80b59..4e57da1ee2 100644 --- a/x/wasm/migrations/v1/store_test.go +++ b/x/wasm/migrations/v1/store_test.go @@ -15,7 +15,7 @@ import ( ) func TestMigrate1To2(t *testing.T) { - const AvailableCapabilities = "iterator,staking,stargate,cosmwasm_1_1" + var AvailableCapabilities = []string{"iterator", "staking", "stargate", "cosmwasm_1_1"} ctx, keepers := keeper.CreateTestInput(t, false, AvailableCapabilities) wasmKeeper := keepers.WasmKeeper diff --git a/x/wasm/migrations/v3/store_test.go b/x/wasm/migrations/v3/store_test.go index 0bd217d299..4f7100f67b 100644 --- a/x/wasm/migrations/v3/store_test.go +++ b/x/wasm/migrations/v3/store_test.go @@ -19,7 +19,7 @@ import ( ) func TestMigrate3To4(t *testing.T) { - const AvailableCapabilities = "iterator,staking,stargate,cosmwasm_1_1" + var AvailableCapabilities = []string{"iterator", "staking", "stargate", "cosmwasm_1_1"} ctx, keepers := keeper.CreateTestInput(t, false, AvailableCapabilities) store := ctx.KVStore(keepers.WasmStoreKey) cdc := moduletestutil.MakeTestEncodingConfig(wasm.AppModuleBasic{}).Codec diff --git a/x/wasm/module_test.go b/x/wasm/module_test.go index c08ab1455e..63e8f5cd90 100644 --- a/x/wasm/module_test.go +++ b/x/wasm/module_test.go @@ -63,7 +63,7 @@ func setupTest(t *testing.T) testData { InstantiateDefaultPermission: v2.AccessTypeEverybody, } - ctx, keepers := keeper.CreateTestInput(t, false, "iterator,staking,stargate,cosmwasm_1_1,cosmwasm_1_2,cosmwasm_1_3,cosmwasm_1_4") + ctx, keepers := keeper.CreateTestInput(t, false, []string{"iterator", "staking", "stargate", "cosmwasm_1_1", "cosmwasm_1_2", "cosmwasm_1_3", "cosmwasm_1_4"}) encConf := keeper.MakeEncodingConfig(t) queryRouter := baseapp.NewGRPCQueryRouter() serviceRouter := baseapp.NewMsgServiceRouter() diff --git a/x/wasm/relay_pingpong_test.go b/x/wasm/relay_pingpong_test.go index 4fcf8926d5..ce5635a8ed 100644 --- a/x/wasm/relay_pingpong_test.go +++ b/x/wasm/relay_pingpong_test.go @@ -262,7 +262,7 @@ func (p player) IBCPacketReceive(_ wasmvm.Checksum, _ wasmvmtypes.Env, msg wasmv return &wasmvmtypes.IBCReceiveResult{ Ok: &wasmvmtypes.IBCReceiveResponse{ - Attributes: wasmvmtypes.EventAttributes{ + Attributes: wasmvmtypes.Array[wasmvmtypes.EventAttribute]{ {Key: "empty-value-test"}, }, Acknowledgement: receivedBall.BuildAck().GetBytes(), diff --git a/x/wasm/relay_test.go b/x/wasm/relay_test.go index e30b276bdc..e461c10739 100644 --- a/x/wasm/relay_test.go +++ b/x/wasm/relay_test.go @@ -634,7 +634,7 @@ func (s *sendEmulatedIBCTransferContract) IBCPacketTimeout(_ wasmvm.Checksum, _ returnTokens := &wasmvmtypes.BankMsg{ Send: &wasmvmtypes.SendMsg{ ToAddress: data.Sender, - Amount: wasmvmtypes.Coins{wasmvmtypes.NewCoin(amount.Uint64(), data.Denom)}, + Amount: wasmvmtypes.Array[wasmvmtypes.Coin]{wasmvmtypes.NewCoin(amount.Uint64(), data.Denom)}, }, } diff --git a/x/wasm/types/gas_register.go b/x/wasm/types/gas_register.go index f77d3c854e..15e9058b1e 100644 --- a/x/wasm/types/gas_register.go +++ b/x/wasm/types/gas_register.go @@ -84,7 +84,7 @@ type GasRegister interface { // ReplyCosts costs to to handle a message reply ReplyCosts(discount bool, reply wasmvmtypes.Reply) storetypes.Gas // EventCosts costs to persist an event - EventCosts(attrs []wasmvmtypes.EventAttribute, events wasmvmtypes.Events) storetypes.Gas + EventCosts(attrs []wasmvmtypes.EventAttribute, events wasmvmtypes.Array[wasmvmtypes.Event]) storetypes.Gas // ToWasmVMGas converts from Cosmos SDK gas units to [CosmWasm gas] (aka. wasmvm gas) // // [CosmWasm gas]: https://github.com/CosmWasm/cosmwasm/blob/v1.3.1/docs/GAS.md @@ -216,7 +216,7 @@ func (g WasmGasRegister) ReplyCosts(discount bool, reply wasmvmtypes.Reply) stor } // EventCosts costs to persist an event -func (g WasmGasRegister) EventCosts(attrs []wasmvmtypes.EventAttribute, events wasmvmtypes.Events) storetypes.Gas { +func (g WasmGasRegister) EventCosts(attrs []wasmvmtypes.EventAttribute, events wasmvmtypes.Array[wasmvmtypes.Event]) storetypes.Gas { gas, remainingFreeTier := g.eventAttributeCosts(attrs, g.c.EventAttributeDataFreeTier) for _, e := range events { gas += g.c.CustomEventCost diff --git a/x/wasm/types/gas_register_test.go b/x/wasm/types/gas_register_test.go index d8612ccfd7..d530fa02ec 100644 --- a/x/wasm/types/gas_register_test.go +++ b/x/wasm/types/gas_register_test.go @@ -258,7 +258,7 @@ func TestEventCosts(t *testing.T) { // most cases are covered in TestReplyCost already. This ensures some edge cases specs := map[string]struct { srcAttrs []wasmvmtypes.EventAttribute - srcEvents wasmvmtypes.Events + srcEvents wasmvmtypes.Array[wasmvmtypes.Event] expGas storetypes.Gas }{ "empty events": { diff --git a/x/wasm/types/types.go b/x/wasm/types/types.go index e59ae1f8a3..4b2a83e0d9 100644 --- a/x/wasm/types/types.go +++ b/x/wasm/types/types.go @@ -281,7 +281,7 @@ func NewEnv(ctx sdk.Context, contractAddr sdk.AccAddress) wasmvmtypes.Env { env := wasmvmtypes.Env{ Block: wasmvmtypes.BlockInfo{ Height: uint64(ctx.BlockHeight()), - Time: uint64(nano), + Time: wasmvmtypes.Uint64(nano), ChainID: ctx.ChainID(), }, Contract: wasmvmtypes.ContractInfo{ diff --git a/x/wasm/types/wasmer_engine.go b/x/wasm/types/wasmer_engine.go index 85f6b2408a..fe5e06fa2b 100644 --- a/x/wasm/types/wasmer_engine.go +++ b/x/wasm/types/wasmer_engine.go @@ -12,22 +12,10 @@ const DefaultMaxQueryStackSize uint32 = 10 // WasmEngine defines the WASM contract runtime engine. type WasmEngine interface { - // Create will compile the wasm code, and store the resulting pre-compile - // as well as the original code. Both can be referenced later via CodeID - // This must be done one time for given code, after which it can be - // instatitated many times, and each instance called many times. - // - // For example, the code for all ERC-20 contracts should be the same. - // This function stores the code for that contract only once, but it can - // be instantiated with custom inputs in the future. - // - // Deprecated: use StoreCode instead. - Create(code wasmvm.WasmCode) (wasmvm.Checksum, error) - // Create will compile the wasm code, and store the resulting pre-compile // as well as the original code. Both can be referenced later via checksum // This must be done one time for given code, after which it can be - // instatitated many times, and each instance called many times. + // instantiated many times, and each instance called many times. // It does the same as StoreCodeUnchecked plus the static checks. StoreCode(code wasmvm.WasmCode) (wasmvm.Checksum, error) From d4e6417dc78a8274a7f24c5cb0f058cab9b4e2a8 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Tue, 6 Feb 2024 18:02:36 +0100 Subject: [PATCH 03/45] Adjust to nested results --- x/wasm/ibc_integration_test.go | 36 ++++--- x/wasm/keeper/handler_plugin_test.go | 10 +- x/wasm/keeper/keeper.go | 34 ++++-- x/wasm/keeper/keeper_test.go | 75 ++++++++------ x/wasm/keeper/querier_test.go | 4 +- x/wasm/keeper/relay.go | 25 +++-- x/wasm/keeper/relay_test.go | 26 ++--- x/wasm/keeper/submsg_test.go | 48 +++++---- x/wasm/keeper/wasmtesting/mock_engine.go | 125 ++++++++++++----------- x/wasm/relay_pingpong_test.go | 48 ++++----- x/wasm/relay_test.go | 44 ++++---- x/wasm/types/wasmer_engine.go | 37 ++++--- 12 files changed, 288 insertions(+), 224 deletions(-) diff --git a/x/wasm/ibc_integration_test.go b/x/wasm/ibc_integration_test.go index cd45168274..8bcd2c3190 100644 --- a/x/wasm/ibc_integration_test.go +++ b/x/wasm/ibc_integration_test.go @@ -52,8 +52,10 @@ func TestOnChanOpenInitVersion(t *testing.T) { for name, spec := range specs { t.Run(name, func(t *testing.T) { myContract := &wasmtesting.MockIBCContractCallbacks{ - IBCChannelOpenFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelOpenMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBC3ChannelOpenResponse, uint64, error) { - return spec.contractRsp, 0, nil + IBCChannelOpenFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelOpenMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCChannelOpenResult, uint64, error) { + return &wasmvmtypes.IBCChannelOpenResult{ + Ok: spec.contractRsp, + }, 0, nil }, } var ( @@ -110,8 +112,10 @@ func TestOnChanOpenTryVersion(t *testing.T) { for name, spec := range specs { t.Run(name, func(t *testing.T) { myContract := &wasmtesting.MockIBCContractCallbacks{ - IBCChannelOpenFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelOpenMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBC3ChannelOpenResponse, uint64, error) { - return spec.contractRsp, 0, nil + IBCChannelOpenFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelOpenMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCChannelOpenResult, uint64, error) { + return &wasmvmtypes.IBCChannelOpenResult{ + Ok: spec.contractRsp, + }, 0, nil }, } var ( @@ -249,11 +253,11 @@ type captureAckTestContractEngine struct { // NewCaptureAckTestContractEngine constructor func NewCaptureAckTestContractEngine() *captureAckTestContractEngine { m := wasmtesting.NewIBCContractMockWasmEngine(&wasmtesting.MockIBCContractCallbacks{ - IBCChannelOpenFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelOpenMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBC3ChannelOpenResponse, uint64, error) { - return &wasmvmtypes.IBC3ChannelOpenResponse{}, 0, nil + IBCChannelOpenFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelOpenMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCChannelOpenResult, uint64, error) { + return &wasmvmtypes.IBCChannelOpenResult{Ok: &wasmvmtypes.IBC3ChannelOpenResponse{}}, 0, nil }, - IBCChannelConnectFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelConnectMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { - return &wasmvmtypes.IBCBasicResponse{}, 0, nil + IBCChannelConnectFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelConnectMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { + return &wasmvmtypes.IBCBasicResult{Ok: &wasmvmtypes.IBCBasicResponse{}}, 0, nil }, }) return &captureAckTestContractEngine{m} @@ -263,18 +267,20 @@ func NewCaptureAckTestContractEngine() *captureAckTestContractEngine { func (x *captureAckTestContractEngine) SubmitIBCPacket(t *testing.T, path *wasmibctesting.Path, chainA *wasmibctesting.TestChain, senderContractAddr sdk.AccAddress, packetData []byte) *[]byte { t.Helper() // prepare a bridge to send an ibc packet by an ordinary wasm execute message - x.MockWasmEngine.ExecuteFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, executeMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { - return &wasmvmtypes.Response{ - Messages: []wasmvmtypes.SubMsg{{ID: 1, ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{IBC: &wasmvmtypes.IBCMsg{SendPacket: &wasmvmtypes.SendPacketMsg{ - ChannelID: path.EndpointA.ChannelID, Data: executeMsg, Timeout: wasmvmtypes.IBCTimeout{Block: &wasmvmtypes.IBCTimeoutBlock{Revision: 1, Height: 10000000}}, - }}}}}, + x.MockWasmEngine.ExecuteFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, executeMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { + return &wasmvmtypes.ContractResult{ + Ok: &wasmvmtypes.Response{ + Messages: []wasmvmtypes.SubMsg{{ID: 1, ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{IBC: &wasmvmtypes.IBCMsg{SendPacket: &wasmvmtypes.SendPacketMsg{ + ChannelID: path.EndpointA.ChannelID, Data: executeMsg, Timeout: wasmvmtypes.IBCTimeout{Block: &wasmvmtypes.IBCTimeoutBlock{Revision: 1, Height: 10000000}}, + }}}}}, + }, }, 0, nil } // capture acknowledgement var gotAck []byte - x.MockWasmEngine.IBCPacketAckFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketAckMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { + x.MockWasmEngine.IBCPacketAckFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketAckMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { gotAck = msg.Acknowledgement.Data - return &wasmvmtypes.IBCBasicResponse{}, 0, nil + return &wasmvmtypes.IBCBasicResult{Ok: &wasmvmtypes.IBCBasicResponse{}}, 0, nil } // start the process diff --git a/x/wasm/keeper/handler_plugin_test.go b/x/wasm/keeper/handler_plugin_test.go index b86c86fd7f..29639f4c25 100644 --- a/x/wasm/keeper/handler_plugin_test.go +++ b/x/wasm/keeper/handler_plugin_test.go @@ -388,10 +388,12 @@ func TestBurnCoinMessageHandlerIntegration(t *testing.T) { for name, spec := range specs { t.Run(name, func(t *testing.T) { ctx, _ = parentCtx.CacheContext() - k.wasmVM = &wasmtesting.MockWasmEngine{ExecuteFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, executeMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { - return &wasmvmtypes.Response{ - Messages: []wasmvmtypes.SubMsg{ - {Msg: wasmvmtypes.CosmosMsg{Bank: &wasmvmtypes.BankMsg{Burn: &spec.msg}}, ReplyOn: wasmvmtypes.ReplyNever}, //nolint:gosec + k.wasmVM = &wasmtesting.MockWasmEngine{ExecuteFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, executeMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { + return &wasmvmtypes.ContractResult{ + Ok: &wasmvmtypes.Response{ + Messages: []wasmvmtypes.SubMsg{ + {Msg: wasmvmtypes.CosmosMsg{Bank: &wasmvmtypes.BankMsg{Burn: &spec.msg}}, ReplyOn: wasmvmtypes.ReplyNever}, //nolint:gosec + }, }, }, 0, nil }} diff --git a/x/wasm/keeper/keeper.go b/x/wasm/keeper/keeper.go index 1e47aa66c6..c169c043df 100644 --- a/x/wasm/keeper/keeper.go +++ b/x/wasm/keeper/keeper.go @@ -169,7 +169,9 @@ func (k Keeper) create(ctx context.Context, creator sdk.AccAddress, wasmCode []b } sdkCtx.GasMeter().ConsumeGas(k.gasRegister.CompileCosts(len(wasmCode)), "Compiling wasm bytecode") - checksum, err = k.wasmVM.StoreCode(wasmCode) + gas := k.runtimeGasForContract(sdkCtx) + checksum, gasUsed, err := k.wasmVM.StoreCode(wasmCode, gas) + k.consumeRuntimeGas(sdkCtx, gasUsed) if err != nil { return 0, checksum, errorsmod.Wrap(types.ErrCreateFailed, err.Error()) } @@ -322,6 +324,9 @@ func (k Keeper) instantiate( if err != nil { return nil, nil, errorsmod.Wrap(types.ErrInstantiateFailed, err.Error()) } + if res.Err != "" { + return nil, nil, errorsmod.Wrap(types.ErrInstantiateFailed, res.Err) + } // persist instance first createdAt := types.NewAbsoluteTxPosition(sdkCtx) @@ -365,7 +370,7 @@ func (k Keeper) instantiate( )) sdkCtx = types.WithSubMsgAuthzPolicy(sdkCtx, authPolicy.SubMessageAuthorizationPolicy(types.AuthZActionInstantiate)) - data, err := k.handleContractResponse(sdkCtx, contractAddress, contractInfo.IBCPortID, res.Messages, res.Attributes, res.Data, res.Events) + data, err := k.handleContractResponse(sdkCtx, contractAddress, contractInfo.IBCPortID, res.Ok.Messages, res.Ok.Attributes, res.Ok.Data, res.Ok.Events) if err != nil { return nil, nil, errorsmod.Wrap(err, "dispatch") } @@ -403,13 +408,16 @@ func (k Keeper) execute(ctx context.Context, contractAddress, caller sdk.AccAddr if execErr != nil { return nil, errorsmod.Wrap(types.ErrExecuteFailed, execErr.Error()) } + if res.Err != "" { + return nil, errorsmod.Wrap(types.ErrExecuteFailed, res.Err) + } sdkCtx.EventManager().EmitEvent(sdk.NewEvent( types.EventTypeExecute, sdk.NewAttribute(types.AttributeKeyContractAddr, contractAddress.String()), )) - data, err := k.handleContractResponse(sdkCtx, contractAddress, contractInfo.IBCPortID, res.Messages, res.Attributes, res.Data, res.Events) + data, err := k.handleContractResponse(sdkCtx, contractAddress, contractInfo.IBCPortID, res.Ok.Messages, res.Ok.Attributes, res.Ok.Data, res.Ok.Events) if err != nil { return nil, errorsmod.Wrap(err, "dispatch") } @@ -477,6 +485,9 @@ func (k Keeper) migrate( if err != nil { return nil, errorsmod.Wrap(types.ErrMigrationFailed, err.Error()) } + if res.Err != "" { + return nil, errorsmod.Wrap(types.ErrMigrationFailed, res.Err) + } // delete old secondary index entry err = k.removeFromContractCodeSecondaryIndex(ctx, contractAddress, k.mustGetLastContractHistoryEntry(sdkCtx, contractAddress)) if err != nil { @@ -501,7 +512,7 @@ func (k Keeper) migrate( )) sdkCtx = types.WithSubMsgAuthzPolicy(sdkCtx, authZ.SubMessageAuthorizationPolicy(types.AuthZActionMigrateContract)) - data, err := k.handleContractResponse(sdkCtx, contractAddress, contractInfo.IBCPortID, res.Messages, res.Attributes, res.Data, res.Events) + data, err := k.handleContractResponse(sdkCtx, contractAddress, contractInfo.IBCPortID, res.Ok.Messages, res.Ok.Attributes, res.Ok.Data, res.Ok.Events) if err != nil { return nil, errorsmod.Wrap(err, "dispatch") } @@ -539,6 +550,9 @@ func (k Keeper) Sudo(ctx context.Context, contractAddress sdk.AccAddress, msg [] if execErr != nil { return nil, errorsmod.Wrap(types.ErrExecuteFailed, execErr.Error()) } + if res.Err != "" { + return nil, errorsmod.Wrap(types.ErrMigrationFailed, res.Err) + } sdkCtx.EventManager().EmitEvent(sdk.NewEvent( types.EventTypeSudo, @@ -546,7 +560,7 @@ func (k Keeper) Sudo(ctx context.Context, contractAddress sdk.AccAddress, msg [] )) // sudo submessages are executed with the default authorization policy - data, err := k.handleContractResponse(sdkCtx, contractAddress, contractInfo.IBCPortID, res.Messages, res.Attributes, res.Data, res.Events) + data, err := k.handleContractResponse(sdkCtx, contractAddress, contractInfo.IBCPortID, res.Ok.Messages, res.Ok.Attributes, res.Ok.Data, res.Ok.Events) if err != nil { return nil, errorsmod.Wrap(err, "dispatch") } @@ -576,13 +590,16 @@ func (k Keeper) reply(ctx sdk.Context, contractAddress sdk.AccAddress, reply was if execErr != nil { return nil, errorsmod.Wrap(types.ErrExecuteFailed, execErr.Error()) } + if res.Err != "" { + return nil, errorsmod.Wrap(types.ErrMigrationFailed, res.Err) + } ctx.EventManager().EmitEvent(sdk.NewEvent( types.EventTypeReply, sdk.NewAttribute(types.AttributeKeyContractAddr, contractAddress.String()), )) - data, err := k.handleContractResponse(ctx, contractAddress, contractInfo.IBCPortID, res.Messages, res.Attributes, res.Data, res.Events) + data, err := k.handleContractResponse(ctx, contractAddress, contractInfo.IBCPortID, res.Ok.Messages, res.Ok.Attributes, res.Ok.Data, res.Ok.Events) if err != nil { return nil, errorsmod.Wrap(err, "dispatch") } @@ -759,7 +776,10 @@ func (k Keeper) QuerySmart(ctx context.Context, contractAddr sdk.AccAddress, req if qErr != nil { return nil, errorsmod.Wrap(types.ErrQueryFailed, qErr.Error()) } - return queryResult, nil + if queryResult.Err != "" { + return nil, errorsmod.Wrap(types.ErrMigrationFailed, queryResult.Err) + } + return queryResult.Ok, nil } func checkAndIncreaseQueryStackSize(ctx context.Context, maxQueryStackSize uint32) (sdk.Context, error) { diff --git a/x/wasm/keeper/keeper_test.go b/x/wasm/keeper/keeper_test.go index fefed2726a..cb7d11be10 100644 --- a/x/wasm/keeper/keeper_test.go +++ b/x/wasm/keeper/keeper_test.go @@ -716,8 +716,8 @@ func TestInstantiateWithContractDataResponse(t *testing.T) { ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) wasmEngineMock := &wasmtesting.MockWasmEngine{ - InstantiateFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { - return &wasmvmtypes.Response{Data: []byte("my-response-data")}, 0, nil + InstantiateFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Data: []byte("my-response-data")}}, 0, nil }, AnalyzeCodeFn: wasmtesting.WithoutIBCAnalyzeFn, StoreCodeFn: wasmtesting.NoOpStoreCodeFn, @@ -741,10 +741,10 @@ func TestInstantiateWithContractFactoryChildQueriesParent(t *testing.T) { keeper := keepers.WasmKeeper var instantiationCount int - callbacks := make([]func(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error), 2) + callbacks := make([]func(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error), 2) wasmEngineMock := &wasmtesting.MockWasmEngine{ // dispatch instantiation calls to callbacks - InstantiateFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + InstantiateFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { require.Greater(t, len(callbacks), instantiationCount, "unexpected call to instantiation") do := callbacks[instantiationCount] instantiationCount++ @@ -764,24 +764,28 @@ func TestInstantiateWithContractFactoryChildQueriesParent(t *testing.T) { example := StoreRandomContract(t, ctx, keepers, wasmEngineMock) // factory contract - callbacks[0] = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + callbacks[0] = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { t.Log("called factory") - return &wasmvmtypes.Response{Data: []byte("parent"), Messages: []wasmvmtypes.SubMsg{ - { - ID: 1, ReplyOn: wasmvmtypes.ReplyNever, - Msg: wasmvmtypes.CosmosMsg{ - Wasm: &wasmvmtypes.WasmMsg{ - Instantiate: &wasmvmtypes.InstantiateMsg{CodeID: example.CodeID, Msg: []byte(`{}`), Label: "child"}, + return &wasmvmtypes.ContractResult{ + Ok: &wasmvmtypes.Response{ + Data: []byte("parent"), + Messages: []wasmvmtypes.SubMsg{ + { + ID: 1, ReplyOn: wasmvmtypes.ReplyNever, + Msg: wasmvmtypes.CosmosMsg{ + Wasm: &wasmvmtypes.WasmMsg{ + Instantiate: &wasmvmtypes.InstantiateMsg{CodeID: example.CodeID, Msg: []byte(`{}`), Label: "child"}, + }, + }, }, - }, - }, - }}, 0, nil + }}, + }, 0, nil } // child contract var capturedSenderAddr string var capturedCodeInfo []byte - callbacks[1] = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + callbacks[1] = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { t.Log("called child") capturedSenderAddr = info.Sender var err error @@ -791,7 +795,7 @@ func TestInstantiateWithContractFactoryChildQueriesParent(t *testing.T) { }, }, gasLimit) require.NoError(t, err) - return &wasmvmtypes.Response{Data: []byte("child")}, 0, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Data: []byte("child")}}, 0, nil } // when @@ -1474,8 +1478,8 @@ func TestIterateContractsByCode(t *testing.T) { func TestIterateContractsByCodeWithMigration(t *testing.T) { // mock migration so that it does not fail when migrate example1 to example2.codeID - mockWasmVM := wasmtesting.MockWasmEngine{MigrateFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, migrateMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { - return &wasmvmtypes.Response{}, 1, nil + mockWasmVM := wasmtesting.MockWasmEngine{MigrateFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, migrateMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{}}, 1, nil }} wasmtesting.MakeInstantiable(&mockWasmVM) ctx, keepers := CreateTestInput(t, false, AvailableCapabilities, WithWasmEngine(&mockWasmVM)) @@ -1844,18 +1848,20 @@ func TestPinnedContractLoops(t *testing.T) { require.NoError(t, k.pinCode(ctx, example.CodeID)) var loops int anyMsg := []byte(`{}`) - mock.ExecuteFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, executeMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + mock.ExecuteFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, executeMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { loops++ - return &wasmvmtypes.Response{ - Messages: []wasmvmtypes.SubMsg{ - { - ID: 1, - ReplyOn: wasmvmtypes.ReplyNever, - Msg: wasmvmtypes.CosmosMsg{ - Wasm: &wasmvmtypes.WasmMsg{ - Execute: &wasmvmtypes.ExecuteMsg{ - ContractAddr: example.Contract.String(), - Msg: anyMsg, + return &wasmvmtypes.ContractResult{ + Ok: &wasmvmtypes.Response{ + Messages: []wasmvmtypes.SubMsg{ + { + ID: 1, + ReplyOn: wasmvmtypes.ReplyNever, + Msg: wasmvmtypes.CosmosMsg{ + Wasm: &wasmvmtypes.WasmMsg{ + Execute: &wasmvmtypes.ExecuteMsg{ + ContractAddr: example.Contract.String(), + Msg: anyMsg, + }, }, }, }, @@ -2007,7 +2013,12 @@ func TestReply(t *testing.T) { } for name, spec := range specs { t.Run(name, func(t *testing.T) { - mock.ReplyFn = spec.replyFn + mock.ReplyFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, reply wasmvmtypes.Reply, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { + resp, gasUsed, err := spec.replyFn(codeID, env, reply, store, goapi, querier, gasMeter, gasLimit, deserCost) + return &wasmvmtypes.ContractResult{ + Ok: resp, + }, gasUsed, err + } em := sdk.NewEventManager() gotData, gotErr := k.reply(ctx.WithEventManager(em), example.Contract, wasmvmtypes.Reply{}) if spec.expErr { @@ -2039,12 +2050,12 @@ func TestQueryIsolation(t *testing.T) { }).apply(k) // when - mock.ReplyFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, reply wasmvmtypes.Reply, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + mock.ReplyFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, reply wasmvmtypes.Reply, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { _, err := querier.Query(wasmvmtypes.QueryRequest{ Custom: []byte(`{}`), }, 10000*types.DefaultGasMultiplier) require.NoError(t, err) - return &wasmvmtypes.Response{}, 0, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{}}, 0, nil } em := sdk.NewEventManager() _, gotErr := k.reply(ctx.WithEventManager(em), example.Contract, wasmvmtypes.Reply{}) diff --git a/x/wasm/keeper/querier_test.go b/x/wasm/keeper/querier_test.go index c81a32a449..afd4ad3cc5 100644 --- a/x/wasm/keeper/querier_test.go +++ b/x/wasm/keeper/querier_test.go @@ -198,9 +198,9 @@ func TestQuerySmartContractPanics(t *testing.T) { } for msg, spec := range specs { t.Run(msg, func(t *testing.T) { - keepers.WasmKeeper.wasmVM = &wasmtesting.MockWasmEngine{QueryFn: func(checksum wasmvm.Checksum, env wasmvmtypes.Env, queryMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) ([]byte, uint64, error) { + keepers.WasmKeeper.wasmVM = &wasmtesting.MockWasmEngine{QueryFn: func(checksum wasmvm.Checksum, env wasmvmtypes.Env, queryMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.QueryResult, uint64, error) { spec.doInContract() - return nil, 0, nil + return &wasmvmtypes.QueryResult{}, 0, nil }} // when q := Querier(keepers.WasmKeeper) diff --git a/x/wasm/keeper/relay.go b/x/wasm/keeper/relay.go index 9f4c86e153..c68171b9e8 100644 --- a/x/wasm/keeper/relay.go +++ b/x/wasm/keeper/relay.go @@ -42,8 +42,8 @@ func (k Keeper) OnOpenChannel( if execErr != nil { return "", errorsmod.Wrap(types.ErrExecuteFailed, execErr.Error()) } - if res != nil { - return res.Version, nil + if res != nil && res.Ok != nil { + return res.Ok.Version, nil } return "", nil } @@ -75,8 +75,11 @@ func (k Keeper) OnConnectChannel( if execErr != nil { return errorsmod.Wrap(types.ErrExecuteFailed, execErr.Error()) } + if res.Err != "" { + return errorsmod.Wrap(types.ErrExecuteFailed, res.Err) + } - return k.handleIBCBasicContractResponse(ctx, contractAddr, contractInfo.IBCPortID, res) + return k.handleIBCBasicContractResponse(ctx, contractAddr, contractInfo.IBCPortID, res.Ok) } // OnCloseChannel calls the contract to let it know the IBC channel is closed. @@ -106,8 +109,11 @@ func (k Keeper) OnCloseChannel( if execErr != nil { return errorsmod.Wrap(types.ErrExecuteFailed, execErr.Error()) } + if res.Err != "" { + return errorsmod.Wrap(types.ErrExecuteFailed, res.Err) + } - return k.handleIBCBasicContractResponse(ctx, contractAddr, contractInfo.IBCPortID, res) + return k.handleIBCBasicContractResponse(ctx, contractAddr, contractInfo.IBCPortID, res.Ok) } // OnRecvPacket calls the contract to process the incoming IBC packet. The contract fully owns the data processing and @@ -194,7 +200,11 @@ func (k Keeper) OnAckPacket( if execErr != nil { return errorsmod.Wrap(types.ErrExecuteFailed, execErr.Error()) } - return k.handleIBCBasicContractResponse(ctx, contractAddr, contractInfo.IBCPortID, res) + if res.Err != "" { + return errorsmod.Wrap(types.ErrExecuteFailed, res.Err) + } + + return k.handleIBCBasicContractResponse(ctx, contractAddr, contractInfo.IBCPortID, res.Ok) } // OnTimeoutPacket calls the contract to let it know the packet was never received on the destination chain within @@ -221,8 +231,11 @@ func (k Keeper) OnTimeoutPacket( if execErr != nil { return errorsmod.Wrap(types.ErrExecuteFailed, execErr.Error()) } + if res.Err != "" { + return errorsmod.Wrap(types.ErrExecuteFailed, res.Err) + } - return k.handleIBCBasicContractResponse(ctx, contractAddr, contractInfo.IBCPortID, res) + return k.handleIBCBasicContractResponse(ctx, contractAddr, contractInfo.IBCPortID, res.Ok) } func (k Keeper) handleIBCBasicContractResponse(ctx sdk.Context, addr sdk.AccAddress, id string, res *wasmvmtypes.IBCBasicResponse) error { diff --git a/x/wasm/keeper/relay_test.go b/x/wasm/keeper/relay_test.go index 4c15816208..8fbd83be3a 100644 --- a/x/wasm/keeper/relay_test.go +++ b/x/wasm/keeper/relay_test.go @@ -59,9 +59,9 @@ func TestOnOpenChannel(t *testing.T) { t.Run(name, func(t *testing.T) { myChannel := wasmvmtypes.IBCChannel{Version: "my test channel"} myMsg := wasmvmtypes.IBCChannelOpenMsg{OpenTry: &wasmvmtypes.IBCOpenTry{Channel: myChannel, CounterpartyVersion: "foo"}} - m.IBCChannelOpenFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelOpenMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBC3ChannelOpenResponse, uint64, error) { + m.IBCChannelOpenFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelOpenMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCChannelOpenResult, uint64, error) { assert.Equal(t, myMsg, msg) - return &wasmvmtypes.IBC3ChannelOpenResponse{}, spec.contractGas * types.DefaultGasMultiplier, spec.contractErr + return &wasmvmtypes.IBCChannelOpenResult{Ok: &wasmvmtypes.IBC3ChannelOpenResponse{}}, spec.contractGas * types.DefaultGasMultiplier, spec.contractErr } ctx, _ := parentCtx.CacheContext() @@ -156,9 +156,9 @@ func TestOnConnectChannel(t *testing.T) { t.Run(name, func(t *testing.T) { myChannel := wasmvmtypes.IBCChannel{Version: "my test channel"} myMsg := wasmvmtypes.IBCChannelConnectMsg{OpenConfirm: &wasmvmtypes.IBCOpenConfirm{Channel: myChannel}} - m.IBCChannelConnectFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelConnectMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { + m.IBCChannelConnectFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelConnectMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { assert.Equal(t, msg, myMsg) - return spec.contractResp, myContractGas * types.DefaultGasMultiplier, spec.contractErr + return &wasmvmtypes.IBCBasicResult{Ok: spec.contractResp}, myContractGas * types.DefaultGasMultiplier, spec.contractErr } ctx, _ := parentCtx.CacheContext() @@ -268,9 +268,9 @@ func TestOnCloseChannel(t *testing.T) { t.Run(name, func(t *testing.T) { myChannel := wasmvmtypes.IBCChannel{Version: "my test channel"} myMsg := wasmvmtypes.IBCChannelCloseMsg{CloseInit: &wasmvmtypes.IBCCloseInit{Channel: myChannel}} - m.IBCChannelCloseFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelCloseMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { + m.IBCChannelCloseFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelCloseMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { assert.Equal(t, msg, myMsg) - return spec.contractResp, myContractGas * types.DefaultGasMultiplier, spec.contractErr + return &wasmvmtypes.IBCBasicResult{Ok: spec.contractResp}, myContractGas * types.DefaultGasMultiplier, spec.contractErr } ctx, _ := parentCtx.CacheContext() @@ -325,7 +325,7 @@ func TestOnRecvPacket(t *testing.T) { contractResp *wasmvmtypes.IBCReceiveResult contractErr error overwriteMessenger *wasmtesting.MockMessageHandler - mockReplyFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, reply wasmvmtypes.Reply, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) + mockReplyFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, reply wasmvmtypes.Reply, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) expContractGas storetypes.Gas expAck []byte expErr bool @@ -426,8 +426,8 @@ func TestOnRecvPacket(t *testing.T) { Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyAlways, Msg: wasmvmtypes.CosmosMsg{Bank: &wasmvmtypes.BankMsg{}}}}, }, }, - mockReplyFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, reply wasmvmtypes.Reply, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { - return &wasmvmtypes.Response{Data: []byte("myBetterAck")}, 0, nil + mockReplyFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, reply wasmvmtypes.Reply, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Data: []byte("myBetterAck")}}, 0, nil }, expAck: []byte("myBetterAck"), expEventTypes: []string{types.EventTypeReply}, @@ -567,9 +567,9 @@ func TestOnAckPacket(t *testing.T) { for name, spec := range specs { t.Run(name, func(t *testing.T) { myAck := wasmvmtypes.IBCPacketAckMsg{Acknowledgement: wasmvmtypes.IBCAcknowledgement{Data: []byte("myAck")}} - m.IBCPacketAckFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketAckMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { + m.IBCPacketAckFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketAckMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { assert.Equal(t, myAck, msg) - return spec.contractResp, myContractGas * types.DefaultGasMultiplier, spec.contractErr + return &wasmvmtypes.IBCBasicResult{Ok: spec.contractResp}, myContractGas * types.DefaultGasMultiplier, spec.contractErr } ctx, _ := parentCtx.CacheContext() @@ -687,9 +687,9 @@ func TestOnTimeoutPacket(t *testing.T) { for name, spec := range specs { t.Run(name, func(t *testing.T) { myPacket := wasmvmtypes.IBCPacket{Data: []byte("my test packet")} - m.IBCPacketTimeoutFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketTimeoutMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { + m.IBCPacketTimeoutFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketTimeoutMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { assert.Equal(t, myPacket, msg.Packet) - return spec.contractResp, myContractGas * types.DefaultGasMultiplier, spec.contractErr + return &wasmvmtypes.IBCBasicResult{Ok: spec.contractResp}, myContractGas * types.DefaultGasMultiplier, spec.contractErr } ctx, _ := parentCtx.CacheContext() diff --git a/x/wasm/keeper/submsg_test.go b/x/wasm/keeper/submsg_test.go index 9060ac6649..75d1519b52 100644 --- a/x/wasm/keeper/submsg_test.go +++ b/x/wasm/keeper/submsg_test.go @@ -563,20 +563,22 @@ func TestInstantiateGovSubMsgAuthzPropagated(t *testing.T) { wasmtesting.MakeInstantiable(mockWasmVM) var instanceLevel int // mock wasvm to return new instantiate msgs with the response - mockWasmVM.InstantiateFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + mockWasmVM.InstantiateFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { if instanceLevel == 2 { - return &wasmvmtypes.Response{}, 0, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{}}, 0, nil } instanceLevel++ submsgPayload := fmt.Sprintf(`{"sub":%d}`, instanceLevel) - return &wasmvmtypes.Response{ - Messages: []wasmvmtypes.SubMsg{ - { - ReplyOn: wasmvmtypes.ReplyNever, - Msg: wasmvmtypes.CosmosMsg{ - Wasm: &wasmvmtypes.WasmMsg{Instantiate: &wasmvmtypes.InstantiateMsg{ - CodeID: 1, Msg: []byte(submsgPayload), Label: "from sub-msg", - }}, + return &wasmvmtypes.ContractResult{ + Ok: &wasmvmtypes.Response{ + Messages: []wasmvmtypes.SubMsg{ + { + ReplyOn: wasmvmtypes.ReplyNever, + Msg: wasmvmtypes.CosmosMsg{ + Wasm: &wasmvmtypes.WasmMsg{Instantiate: &wasmvmtypes.InstantiateMsg{ + CodeID: 1, Msg: []byte(submsgPayload), Label: "from sub-msg", + }}, + }, }, }, }, @@ -650,22 +652,24 @@ func TestMigrateGovSubMsgAuthzPropagated(t *testing.T) { var instanceLevel int // mock wasvm to return new migrate msgs with the response - mockWasmVM.MigrateFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, migrateMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + mockWasmVM.MigrateFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, migrateMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { if instanceLevel == 1 { - return &wasmvmtypes.Response{}, 0, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{}}, 0, nil } instanceLevel++ submsgPayload := fmt.Sprintf(`{"sub":%d}`, instanceLevel) - return &wasmvmtypes.Response{ - Messages: []wasmvmtypes.SubMsg{ - { - ReplyOn: wasmvmtypes.ReplyNever, - Msg: wasmvmtypes.CosmosMsg{ - Wasm: &wasmvmtypes.WasmMsg{Migrate: &wasmvmtypes.MigrateMsg{ - ContractAddr: example1.Contract.String(), - NewCodeID: example2.CodeID, - Msg: []byte(submsgPayload), - }}, + return &wasmvmtypes.ContractResult{ + Ok: &wasmvmtypes.Response{ + Messages: []wasmvmtypes.SubMsg{ + { + ReplyOn: wasmvmtypes.ReplyNever, + Msg: wasmvmtypes.CosmosMsg{ + Wasm: &wasmvmtypes.WasmMsg{Migrate: &wasmvmtypes.MigrateMsg{ + ContractAddr: example1.Contract.String(), + NewCodeID: example2.CodeID, + Msg: []byte(submsgPayload), + }}, + }, }, }, }, diff --git a/x/wasm/keeper/wasmtesting/mock_engine.go b/x/wasm/keeper/wasmtesting/mock_engine.go index 64fad36264..1b3465bfae 100644 --- a/x/wasm/keeper/wasmtesting/mock_engine.go +++ b/x/wasm/keeper/wasmtesting/mock_engine.go @@ -12,48 +12,53 @@ import ( "github.com/CosmWasm/wasmd/x/wasm/types" ) +const ( + // The amount of gas to be consumed by the default MockWasmEngine.StoreCode functions per byte + MockStoreCodeCostPerByte = 3 * 140_000 +) + var _ types.WasmEngine = &MockWasmEngine{} // MockWasmEngine implements types.WasmEngine for testing purpose. One or multiple messages can be stubbed. // Without a stub function a panic is thrown. type MockWasmEngine struct { - StoreCodeFn func(codeID wasmvm.WasmCode) (wasmvm.Checksum, error) + StoreCodeFn func(codeID wasmvm.WasmCode, gasLimit uint64) (wasmvm.Checksum, uint64, error) StoreCodeUncheckedFn func(codeID wasmvm.WasmCode) (wasmvm.Checksum, error) AnalyzeCodeFn func(codeID wasmvm.Checksum) (*wasmvmtypes.AnalysisReport, error) - InstantiateFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) - ExecuteFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, executeMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) - QueryFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, queryMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) ([]byte, uint64, error) - MigrateFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, migrateMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) - SudoFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, sudoMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) - ReplyFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, reply wasmvmtypes.Reply, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) + InstantiateFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) + ExecuteFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, executeMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) + QueryFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, queryMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.QueryResult, uint64, error) + MigrateFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, migrateMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) + SudoFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, sudoMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) + ReplyFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, reply wasmvmtypes.Reply, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) GetCodeFn func(codeID wasmvm.Checksum) (wasmvm.WasmCode, error) CleanupFn func() - IBCChannelOpenFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelOpenMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBC3ChannelOpenResponse, uint64, error) - IBCChannelConnectFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelConnectMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) - IBCChannelCloseFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelCloseMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) + IBCChannelOpenFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelOpenMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCChannelOpenResult, uint64, error) + IBCChannelConnectFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelConnectMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) + IBCChannelCloseFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelCloseMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) IBCPacketReceiveFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketReceiveMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCReceiveResult, uint64, error) - IBCPacketAckFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketAckMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) - IBCPacketTimeoutFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketTimeoutMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) + IBCPacketAckFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketAckMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) + IBCPacketTimeoutFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketTimeoutMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) PinFn func(checksum wasmvm.Checksum) error UnpinFn func(checksum wasmvm.Checksum) error GetMetricsFn func() (*wasmvmtypes.Metrics, error) } -func (m *MockWasmEngine) IBCChannelOpen(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelOpenMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBC3ChannelOpenResponse, uint64, error) { +func (m *MockWasmEngine) IBCChannelOpen(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelOpenMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCChannelOpenResult, uint64, error) { if m.IBCChannelOpenFn == nil { panic("not supposed to be called!") } return m.IBCChannelOpenFn(codeID, env, msg, store, goapi, querier, gasMeter, gasLimit, deserCost) } -func (m *MockWasmEngine) IBCChannelConnect(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelConnectMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { +func (m *MockWasmEngine) IBCChannelConnect(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelConnectMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { if m.IBCChannelConnectFn == nil { panic("not supposed to be called!") } return m.IBCChannelConnectFn(codeID, env, msg, store, goapi, querier, gasMeter, gasLimit, deserCost) } -func (m *MockWasmEngine) IBCChannelClose(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelCloseMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { +func (m *MockWasmEngine) IBCChannelClose(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelCloseMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { if m.IBCChannelCloseFn == nil { panic("not supposed to be called!") } @@ -67,30 +72,25 @@ func (m *MockWasmEngine) IBCPacketReceive(codeID wasmvm.Checksum, env wasmvmtype return m.IBCPacketReceiveFn(codeID, env, msg, store, goapi, querier, gasMeter, gasLimit, deserCost) } -func (m *MockWasmEngine) IBCPacketAck(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketAckMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { +func (m *MockWasmEngine) IBCPacketAck(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketAckMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { if m.IBCPacketAckFn == nil { panic("not supposed to be called!") } return m.IBCPacketAckFn(codeID, env, msg, store, goapi, querier, gasMeter, gasLimit, deserCost) } -func (m *MockWasmEngine) IBCPacketTimeout(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketTimeoutMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { +func (m *MockWasmEngine) IBCPacketTimeout(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketTimeoutMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { if m.IBCPacketTimeoutFn == nil { panic("not supposed to be called!") } return m.IBCPacketTimeoutFn(codeID, env, msg, store, goapi, querier, gasMeter, gasLimit, deserCost) } -// Deprecated: use StoreCode instead. -func (m *MockWasmEngine) Create(codeID wasmvm.WasmCode) (wasmvm.Checksum, error) { - panic("Deprecated: use StoreCode instead") -} - -func (m *MockWasmEngine) StoreCode(codeID wasmvm.WasmCode) (wasmvm.Checksum, error) { +func (m *MockWasmEngine) StoreCode(codeID wasmvm.WasmCode, gasLimit uint64) (wasmvm.Checksum, uint64, error) { if m.StoreCodeFn == nil { panic("not supposed to be called!") } - return m.StoreCodeFn(codeID) + return m.StoreCodeFn(codeID, gasLimit) } func (m *MockWasmEngine) StoreCodeUnchecked(codeID wasmvm.WasmCode) (wasmvm.Checksum, error) { @@ -107,42 +107,42 @@ func (m *MockWasmEngine) AnalyzeCode(codeID wasmvm.Checksum) (*wasmvmtypes.Analy return m.AnalyzeCodeFn(codeID) } -func (m *MockWasmEngine) Instantiate(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { +func (m *MockWasmEngine) Instantiate(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { if m.InstantiateFn == nil { panic("not supposed to be called!") } return m.InstantiateFn(codeID, env, info, initMsg, store, goapi, querier, gasMeter, gasLimit, deserCost) } -func (m *MockWasmEngine) Execute(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, executeMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { +func (m *MockWasmEngine) Execute(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, executeMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { if m.ExecuteFn == nil { panic("not supposed to be called!") } return m.ExecuteFn(codeID, env, info, executeMsg, store, goapi, querier, gasMeter, gasLimit, deserCost) } -func (m *MockWasmEngine) Query(codeID wasmvm.Checksum, env wasmvmtypes.Env, queryMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) ([]byte, uint64, error) { +func (m *MockWasmEngine) Query(codeID wasmvm.Checksum, env wasmvmtypes.Env, queryMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.QueryResult, uint64, error) { if m.QueryFn == nil { panic("not supposed to be called!") } return m.QueryFn(codeID, env, queryMsg, store, goapi, querier, gasMeter, gasLimit, deserCost) } -func (m *MockWasmEngine) Migrate(codeID wasmvm.Checksum, env wasmvmtypes.Env, migrateMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { +func (m *MockWasmEngine) Migrate(codeID wasmvm.Checksum, env wasmvmtypes.Env, migrateMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { if m.MigrateFn == nil { panic("not supposed to be called!") } return m.MigrateFn(codeID, env, migrateMsg, store, goapi, querier, gasMeter, gasLimit, deserCost) } -func (m *MockWasmEngine) Sudo(codeID wasmvm.Checksum, env wasmvmtypes.Env, sudoMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { +func (m *MockWasmEngine) Sudo(codeID wasmvm.Checksum, env wasmvmtypes.Env, sudoMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { if m.SudoFn == nil { panic("not supposed to be called!") } return m.SudoFn(codeID, env, sudoMsg, store, goapi, querier, gasMeter, gasLimit, deserCost) } -func (m *MockWasmEngine) Reply(codeID wasmvm.Checksum, env wasmvmtypes.Env, reply wasmvmtypes.Reply, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { +func (m *MockWasmEngine) Reply(codeID wasmvm.Checksum, env wasmvmtypes.Env, reply wasmvmtypes.Reply, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { if m.ReplyFn == nil { panic("not supposed to be called!") } @@ -189,23 +189,25 @@ var AlwaysPanicMockWasmEngine = &MockWasmEngine{} // SelfCallingInstMockWasmEngine prepares a WasmEngine mock that calls itself on instantiation. func SelfCallingInstMockWasmEngine(executeCalled *bool) *MockWasmEngine { return &MockWasmEngine{ - StoreCodeFn: func(code wasmvm.WasmCode) (wasmvm.Checksum, error) { + StoreCodeFn: func(code wasmvm.WasmCode, gasLimit uint64) (wasmvm.Checksum, uint64, error) { anyCodeID := bytes.Repeat([]byte{0x1}, 32) - return anyCodeID, nil + return anyCodeID, 0, nil }, - InstantiateFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { - return &wasmvmtypes.Response{ - Messages: []wasmvmtypes.SubMsg{ - {Msg: wasmvmtypes.CosmosMsg{ - Wasm: &wasmvmtypes.WasmMsg{Execute: &wasmvmtypes.ExecuteMsg{ContractAddr: env.Contract.Address, Msg: []byte(`{}`)}}, - }}, + InstantiateFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { + return &wasmvmtypes.ContractResult{ + Ok: &wasmvmtypes.Response{ + Messages: []wasmvmtypes.SubMsg{ + {Msg: wasmvmtypes.CosmosMsg{ + Wasm: &wasmvmtypes.WasmMsg{Execute: &wasmvmtypes.ExecuteMsg{ContractAddr: env.Contract.Address, Msg: []byte(`{}`)}}, + }}, + }, }, }, 1, nil }, AnalyzeCodeFn: WithoutIBCAnalyzeFn, - ExecuteFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, executeMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + ExecuteFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, executeMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { *executeCalled = true - return &wasmvmtypes.Response{}, 1, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{}}, 1, nil }, } } @@ -223,7 +225,7 @@ type IBCContractCallbacks interface { gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction, - ) (*wasmvmtypes.IBC3ChannelOpenResponse, uint64, error) + ) (*wasmvmtypes.IBCChannelOpenResult, uint64, error) IBCChannelConnect( codeID wasmvm.Checksum, @@ -235,7 +237,7 @@ type IBCContractCallbacks interface { gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction, - ) (*wasmvmtypes.IBCBasicResponse, uint64, error) + ) (*wasmvmtypes.IBCBasicResult, uint64, error) IBCChannelClose( codeID wasmvm.Checksum, @@ -247,7 +249,7 @@ type IBCContractCallbacks interface { gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction, - ) (*wasmvmtypes.IBCBasicResponse, uint64, error) + ) (*wasmvmtypes.IBCBasicResult, uint64, error) IBCPacketReceive( codeID wasmvm.Checksum, @@ -271,7 +273,7 @@ type IBCContractCallbacks interface { gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction, - ) (*wasmvmtypes.IBCBasicResponse, uint64, error) + ) (*wasmvmtypes.IBCBasicResult, uint64, error) IBCPacketTimeout( codeID wasmvm.Checksum, @@ -283,7 +285,7 @@ type IBCContractCallbacks interface { gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction, - ) (*wasmvmtypes.IBCBasicResponse, uint64, error) + ) (*wasmvmtypes.IBCBasicResult, uint64, error) } type contractExecutable interface { @@ -298,7 +300,7 @@ type contractExecutable interface { gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction, - ) (*wasmvmtypes.Response, uint64, error) + ) (*wasmvmtypes.ContractResult, uint64, error) } // MakeInstantiable adds some noop functions to not fail when contract is used for instantiation @@ -334,15 +336,16 @@ func NewIBCContractMockWasmEngine(c IBCContractCallbacks) *MockWasmEngine { return m } -func HashOnlyStoreCodeFn(code wasmvm.WasmCode) (wasmvm.Checksum, error) { +func HashOnlyStoreCodeFn(code wasmvm.WasmCode, gasLimit uint64) (wasmvm.Checksum, uint64, error) { if code == nil { - return nil, errorsmod.Wrap(types.ErrInvalid, "wasm code must not be nil") + return nil, 0, errorsmod.Wrap(types.ErrInvalid, "wasm code must not be nil") } - return wasmvm.CreateChecksum(code) + checksum, err := wasmvm.CreateChecksum(code) + return checksum, 0, err } -func NoOpInstantiateFn(wasmvm.Checksum, wasmvmtypes.Env, wasmvmtypes.MessageInfo, []byte, wasmvm.KVStore, wasmvm.GoAPI, wasmvm.Querier, wasmvm.GasMeter, uint64, wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { - return &wasmvmtypes.Response{}, 0, nil +func NoOpInstantiateFn(wasmvm.Checksum, wasmvmtypes.Env, wasmvmtypes.MessageInfo, []byte, wasmvm.KVStore, wasmvm.GoAPI, wasmvm.Querier, wasmvm.GasMeter, uint64, wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{}}, 0, nil } func NoOpStoreCodeFn(_ wasmvm.WasmCode) (wasmvm.Checksum, error) { @@ -362,29 +365,29 @@ func WithoutIBCAnalyzeFn(wasmvm.Checksum) (*wasmvmtypes.AnalysisReport, error) { var _ IBCContractCallbacks = &MockIBCContractCallbacks{} type MockIBCContractCallbacks struct { - IBCChannelOpenFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelOpenMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBC3ChannelOpenResponse, uint64, error) - IBCChannelConnectFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelConnectMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) - IBCChannelCloseFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelCloseMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) + IBCChannelOpenFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelOpenMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCChannelOpenResult, uint64, error) + IBCChannelConnectFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelConnectMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) + IBCChannelCloseFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelCloseMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) IBCPacketReceiveFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketReceiveMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCReceiveResult, uint64, error) - IBCPacketAckFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketAckMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) - IBCPacketTimeoutFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketTimeoutMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) + IBCPacketAckFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketAckMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) + IBCPacketTimeoutFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketTimeoutMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) } -func (m MockIBCContractCallbacks) IBCChannelOpen(codeID wasmvm.Checksum, env wasmvmtypes.Env, channel wasmvmtypes.IBCChannelOpenMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBC3ChannelOpenResponse, uint64, error) { +func (m MockIBCContractCallbacks) IBCChannelOpen(codeID wasmvm.Checksum, env wasmvmtypes.Env, channel wasmvmtypes.IBCChannelOpenMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCChannelOpenResult, uint64, error) { if m.IBCChannelOpenFn == nil { panic("not expected to be called") } return m.IBCChannelOpenFn(codeID, env, channel, store, goapi, querier, gasMeter, gasLimit, deserCost) } -func (m MockIBCContractCallbacks) IBCChannelConnect(codeID wasmvm.Checksum, env wasmvmtypes.Env, channel wasmvmtypes.IBCChannelConnectMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { +func (m MockIBCContractCallbacks) IBCChannelConnect(codeID wasmvm.Checksum, env wasmvmtypes.Env, channel wasmvmtypes.IBCChannelConnectMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { if m.IBCChannelConnectFn == nil { panic("not expected to be called") } return m.IBCChannelConnectFn(codeID, env, channel, store, goapi, querier, gasMeter, gasLimit, deserCost) } -func (m MockIBCContractCallbacks) IBCChannelClose(codeID wasmvm.Checksum, env wasmvmtypes.Env, channel wasmvmtypes.IBCChannelCloseMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { +func (m MockIBCContractCallbacks) IBCChannelClose(codeID wasmvm.Checksum, env wasmvmtypes.Env, channel wasmvmtypes.IBCChannelCloseMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { if m.IBCChannelCloseFn == nil { panic("not expected to be called") } @@ -398,14 +401,14 @@ func (m MockIBCContractCallbacks) IBCPacketReceive(codeID wasmvm.Checksum, env w return m.IBCPacketReceiveFn(codeID, env, packet, store, goapi, querier, gasMeter, gasLimit, deserCost) } -func (m MockIBCContractCallbacks) IBCPacketAck(codeID wasmvm.Checksum, env wasmvmtypes.Env, ack wasmvmtypes.IBCPacketAckMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { +func (m MockIBCContractCallbacks) IBCPacketAck(codeID wasmvm.Checksum, env wasmvmtypes.Env, ack wasmvmtypes.IBCPacketAckMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { if m.IBCPacketAckFn == nil { panic("not expected to be called") } return m.IBCPacketAckFn(codeID, env, ack, store, goapi, querier, gasMeter, gasLimit, deserCost) } -func (m MockIBCContractCallbacks) IBCPacketTimeout(codeID wasmvm.Checksum, env wasmvmtypes.Env, packet wasmvmtypes.IBCPacketTimeoutMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { +func (m MockIBCContractCallbacks) IBCPacketTimeout(codeID wasmvm.Checksum, env wasmvmtypes.Env, packet wasmvmtypes.IBCPacketTimeoutMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { if m.IBCPacketTimeoutFn == nil { panic("not expected to be called") } diff --git a/x/wasm/relay_pingpong_test.go b/x/wasm/relay_pingpong_test.go index ce5635a8ed..d06a460714 100644 --- a/x/wasm/relay_pingpong_test.go +++ b/x/wasm/relay_pingpong_test.go @@ -137,7 +137,7 @@ type player struct { // Execute starts the ping pong game // Contracts finds all connected channels and broadcasts a ping message -func (p *player) Execute(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.MessageInfo, executeMsg []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { +func (p *player) Execute(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.MessageInfo, executeMsg []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { p.execCalls++ // start game var start startGame @@ -153,39 +153,41 @@ func (p *player) Execute(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.Mes p.incrementCounter(sentBallsCountKey, store) store.Set(lastBallSentKey, sdk.Uint64ToBigEndian(start.Value)) - return &wasmvmtypes.Response{ - Messages: []wasmvmtypes.SubMsg{ - { - Msg: wasmvmtypes.CosmosMsg{ - IBC: &wasmvmtypes.IBCMsg{ - SendPacket: &wasmvmtypes.SendPacketMsg{ - ChannelID: start.ChannelID, - Data: service.GetBytes(), - Timeout: wasmvmtypes.IBCTimeout{Block: &wasmvmtypes.IBCTimeoutBlock{ - Revision: doNotTimeout.RevisionNumber, - Height: doNotTimeout.RevisionHeight, - }}, + return &wasmvmtypes.ContractResult{ + Ok: &wasmvmtypes.Response{ + Messages: []wasmvmtypes.SubMsg{ + { + Msg: wasmvmtypes.CosmosMsg{ + IBC: &wasmvmtypes.IBCMsg{ + SendPacket: &wasmvmtypes.SendPacketMsg{ + ChannelID: start.ChannelID, + Data: service.GetBytes(), + Timeout: wasmvmtypes.IBCTimeout{Block: &wasmvmtypes.IBCTimeoutBlock{ + Revision: doNotTimeout.RevisionNumber, + Height: doNotTimeout.RevisionHeight, + }}, + }, }, }, + ReplyOn: wasmvmtypes.ReplyNever, }, - ReplyOn: wasmvmtypes.ReplyNever, }, }, }, 0, nil } // OnIBCChannelOpen ensures to accept only configured version -func (p player) IBCChannelOpen(_ wasmvm.Checksum, _ wasmvmtypes.Env, msg wasmvmtypes.IBCChannelOpenMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBC3ChannelOpenResponse, uint64, error) { +func (p player) IBCChannelOpen(_ wasmvm.Checksum, _ wasmvmtypes.Env, msg wasmvmtypes.IBCChannelOpenMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCChannelOpenResult, uint64, error) { if msg.GetChannel().Version != p.actor { - return &wasmvmtypes.IBC3ChannelOpenResponse{}, 0, nil + return &wasmvmtypes.IBCChannelOpenResult{Ok: &wasmvmtypes.IBC3ChannelOpenResponse{}}, 0, nil } - return &wasmvmtypes.IBC3ChannelOpenResponse{}, 0, nil + return &wasmvmtypes.IBCChannelOpenResult{Ok: &wasmvmtypes.IBC3ChannelOpenResponse{}}, 0, nil } // OnIBCChannelConnect persists connection endpoints -func (p player) IBCChannelConnect(_ wasmvm.Checksum, _ wasmvmtypes.Env, msg wasmvmtypes.IBCChannelConnectMsg, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { +func (p player) IBCChannelConnect(_ wasmvm.Checksum, _ wasmvmtypes.Env, msg wasmvmtypes.IBCChannelConnectMsg, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { p.storeEndpoint(store, msg.GetChannel()) - return &wasmvmtypes.IBCBasicResponse{}, 0, nil + return &wasmvmtypes.IBCBasicResult{Ok: &wasmvmtypes.IBCBasicResponse{}}, 0, nil } // connectedChannelsModel is a simple persistence model to store endpoint addresses within the contract's store @@ -210,7 +212,7 @@ func (p player) storeEndpoint(store wasmvm.KVStore, channel wasmvmtypes.IBCChann store.Set(ibcEndpointsKey, bz) } -func (p player) IBCChannelClose(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.IBCChannelCloseMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { +func (p player) IBCChannelClose(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.IBCChannelCloseMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { panic("implement me") } @@ -272,7 +274,7 @@ func (p player) IBCPacketReceive(_ wasmvm.Checksum, _ wasmvmtypes.Env, msg wasmv } // OnIBCPacketAcknowledgement handles the packet acknowledgment frame. Stops the game on an any error -func (p player) IBCPacketAck(_ wasmvm.Checksum, _ wasmvmtypes.Env, msg wasmvmtypes.IBCPacketAckMsg, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { +func (p player) IBCPacketAck(_ wasmvm.Checksum, _ wasmvmtypes.Env, msg wasmvmtypes.IBCPacketAckMsg, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { // parse received data and store var sentBall hit if err := json.Unmarshal(msg.OriginalPacket.Data, &sentBall); err != nil { @@ -291,10 +293,10 @@ func (p player) IBCPacketAck(_ wasmvm.Checksum, _ wasmvmtypes.Env, msg wasmvmtyp } p.incrementCounter(confirmedBallsCountKey, store) - return &wasmvmtypes.IBCBasicResponse{}, 0, nil + return &wasmvmtypes.IBCBasicResult{Ok: &wasmvmtypes.IBCBasicResponse{}}, 0, nil } -func (p player) IBCPacketTimeout(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.IBCPacketTimeoutMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { +func (p player) IBCPacketTimeout(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.IBCPacketTimeoutMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { panic("implement me") } diff --git a/x/wasm/relay_test.go b/x/wasm/relay_test.go index e461c10739..bfb906db6b 100644 --- a/x/wasm/relay_test.go +++ b/x/wasm/relay_test.go @@ -551,9 +551,9 @@ type captureCloseContract struct { closeCalled bool } -func (c *captureCloseContract) IBCChannelClose(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.IBCChannelCloseMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { +func (c *captureCloseContract) IBCChannelClose(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.IBCChannelCloseMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { c.closeCalled = true - return &wasmvmtypes.IBCBasicResponse{}, 1, nil + return &wasmvmtypes.IBCBasicResult{Ok: &wasmvmtypes.IBCBasicResponse{}}, 1, nil } var _ wasmtesting.IBCContractCallbacks = &sendViaIBCTransferContract{} @@ -564,7 +564,7 @@ type sendViaIBCTransferContract struct { t *testing.T } -func (s *sendViaIBCTransferContract) Execute(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.MessageInfo, executeMsg []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { +func (s *sendViaIBCTransferContract) Execute(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.MessageInfo, executeMsg []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { var in startTransfer if err := json.Unmarshal(executeMsg, &in); err != nil { return nil, 0, err @@ -581,7 +581,7 @@ func (s *sendViaIBCTransferContract) Execute(_ wasmvm.Checksum, _ wasmvmtypes.En }, } - return &wasmvmtypes.Response{Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{IBC: ibcMsg}}}}, 0, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{IBC: ibcMsg}}}}}, 0, nil } var _ wasmtesting.IBCContractCallbacks = &sendEmulatedIBCTransferContract{} @@ -594,7 +594,7 @@ type sendEmulatedIBCTransferContract struct { contractAddr string } -func (s *sendEmulatedIBCTransferContract) Execute(_ wasmvm.Checksum, _ wasmvmtypes.Env, info wasmvmtypes.MessageInfo, executeMsg []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { +func (s *sendEmulatedIBCTransferContract) Execute(_ wasmvm.Checksum, _ wasmvmtypes.Env, info wasmvmtypes.MessageInfo, executeMsg []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { var in startTransfer if err := json.Unmarshal(executeMsg, &in); err != nil { return nil, 0, err @@ -616,10 +616,10 @@ func (s *sendEmulatedIBCTransferContract) Execute(_ wasmvm.Checksum, _ wasmvmtyp Timeout: wasmvmtypes.IBCTimeout{Timestamp: in.Timeout}, }, } - return &wasmvmtypes.Response{Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{IBC: ibcMsg}}}}, 0, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{IBC: ibcMsg}}}}}, 0, nil } -func (s *sendEmulatedIBCTransferContract) IBCPacketTimeout(_ wasmvm.Checksum, _ wasmvmtypes.Env, msg wasmvmtypes.IBCPacketTimeoutMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { +func (s *sendEmulatedIBCTransferContract) IBCPacketTimeout(_ wasmvm.Checksum, _ wasmvmtypes.Env, msg wasmvmtypes.IBCPacketTimeoutMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { packet := msg.Packet var data ibctransfertypes.FungibleTokenPacketData @@ -638,7 +638,7 @@ func (s *sendEmulatedIBCTransferContract) IBCPacketTimeout(_ wasmvm.Checksum, _ }, } - return &wasmvmtypes.IBCBasicResponse{Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{Bank: returnTokens}}}}, 0, nil + return &wasmvmtypes.IBCBasicResult{Ok: &wasmvmtypes.IBCBasicResponse{Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{Bank: returnTokens}}}}}, 0, nil } var _ wasmtesting.IBCContractCallbacks = &closeChannelContract{} @@ -647,11 +647,11 @@ type closeChannelContract struct { contractStub } -func (c *closeChannelContract) IBCChannelClose(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.IBCChannelCloseMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { - return &wasmvmtypes.IBCBasicResponse{}, 1, nil +func (c *closeChannelContract) IBCChannelClose(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.IBCChannelCloseMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { + return &wasmvmtypes.IBCBasicResult{Ok: &wasmvmtypes.IBCBasicResponse{}}, 1, nil } -func (c *closeChannelContract) Execute(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.MessageInfo, executeMsg []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { +func (c *closeChannelContract) Execute(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.MessageInfo, executeMsg []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { var in closeIBCChannel if err := json.Unmarshal(executeMsg, &in); err != nil { return nil, 0, err @@ -662,7 +662,7 @@ func (c *closeChannelContract) Execute(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ w }, } - return &wasmvmtypes.Response{Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{IBC: ibcMsg}}}}, 0, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{IBC: ibcMsg}}}}}, 0, nil } type closeIBCChannel struct { @@ -725,7 +725,7 @@ func (c *ackReceiverContract) IBCPacketReceive(_ wasmvm.Checksum, _ wasmvmtypes. return &wasmvmtypes.IBCReceiveResult{Ok: &wasmvmtypes.IBCReceiveResponse{Acknowledgement: ack, Attributes: log}}, 0, nil } -func (c *ackReceiverContract) IBCPacketAck(_ wasmvm.Checksum, _ wasmvmtypes.Env, msg wasmvmtypes.IBCPacketAckMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { +func (c *ackReceiverContract) IBCPacketAck(_ wasmvm.Checksum, _ wasmvmtypes.Env, msg wasmvmtypes.IBCPacketAckMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { var data ibctransfertypes.FungibleTokenPacketData if err := ibctransfertypes.ModuleCdc.UnmarshalJSON(msg.OriginalPacket.Data, &data); err != nil { return nil, 0, err @@ -745,7 +745,7 @@ func (c *ackReceiverContract) IBCPacketAck(_ wasmvm.Checksum, _ wasmvmtypes.Env, return nil, 0, errorsmod.Wrap(err, "within our smart contract") } - return &wasmvmtypes.IBCBasicResponse{}, 0, nil + return &wasmvmtypes.IBCBasicResult{Ok: &wasmvmtypes.IBCBasicResponse{}}, 0, nil } // contract that acts as the receiving side for an ics-20 transfer and always returns a nack. @@ -785,15 +785,15 @@ func (c *errorReceiverContract) IBCPacketReceive(_ wasmvm.Checksum, _ wasmvmtype // simple helper struct that implements connection setup methods. type contractStub struct{} -func (s *contractStub) IBCChannelOpen(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.IBCChannelOpenMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBC3ChannelOpenResponse, uint64, error) { - return &wasmvmtypes.IBC3ChannelOpenResponse{}, 0, nil +func (s *contractStub) IBCChannelOpen(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.IBCChannelOpenMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCChannelOpenResult, uint64, error) { + return &wasmvmtypes.IBCChannelOpenResult{Ok: &wasmvmtypes.IBC3ChannelOpenResponse{}}, 0, nil } -func (s *contractStub) IBCChannelConnect(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.IBCChannelConnectMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { - return &wasmvmtypes.IBCBasicResponse{}, 0, nil +func (s *contractStub) IBCChannelConnect(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.IBCChannelConnectMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { + return &wasmvmtypes.IBCBasicResult{Ok: &wasmvmtypes.IBCBasicResponse{}}, 0, nil } -func (s *contractStub) IBCChannelClose(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.IBCChannelCloseMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { +func (s *contractStub) IBCChannelClose(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.IBCChannelCloseMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { panic("implement me") } @@ -801,11 +801,11 @@ func (s *contractStub) IBCPacketReceive(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ panic("implement me") } -func (s *contractStub) IBCPacketAck(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.IBCPacketAckMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { - return &wasmvmtypes.IBCBasicResponse{}, 0, nil +func (s *contractStub) IBCPacketAck(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.IBCPacketAckMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { + return &wasmvmtypes.IBCBasicResult{Ok: &wasmvmtypes.IBCBasicResponse{}}, 0, nil } -func (s *contractStub) IBCPacketTimeout(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.IBCPacketTimeoutMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { +func (s *contractStub) IBCPacketTimeout(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.IBCPacketTimeoutMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { panic("implement me") } diff --git a/x/wasm/types/wasmer_engine.go b/x/wasm/types/wasmer_engine.go index fe5e06fa2b..08d934de2b 100644 --- a/x/wasm/types/wasmer_engine.go +++ b/x/wasm/types/wasmer_engine.go @@ -2,6 +2,7 @@ package types import ( wasmvm "github.com/CosmWasm/wasmvm/v2" + "github.com/CosmWasm/wasmvm/v2/types" wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" storetypes "cosmossdk.io/store/types" @@ -12,18 +13,20 @@ const DefaultMaxQueryStackSize uint32 = 10 // WasmEngine defines the WASM contract runtime engine. type WasmEngine interface { - // Create will compile the wasm code, and store the resulting pre-compile - // as well as the original code. Both can be referenced later via checksum + // StoreCode will compile the Wasm code, and store the resulting compiled module + // as well as the original code. Both can be referenced later via Checksum. // This must be done one time for given code, after which it can be // instantiated many times, and each instance called many times. - // It does the same as StoreCodeUnchecked plus the static checks. - StoreCode(code wasmvm.WasmCode) (wasmvm.Checksum, error) + // + // Returns both the checksum, as well as the gas cost of compilation (in CosmWasm Gas) or an error. + StoreCode(code wasmvm.WasmCode, gasLimit uint64) (wasmvm.Checksum, uint64, error) - // Create will compile the wasm code, and store the resulting pre-compile + // StoreCodeUnchecked will compile the wasm code, and store the resulting pre-compile // as well as the original code. Both can be referenced later via checksum // This must be done one time for given code, after which it can be - // instatitated many times, and each instance called many times. + // instantiated many times, and each instance called many times. // It does the same as StoreCode but without the static checks. + // Use this for adding code that was checked before, particularly in the case of state sync. StoreCodeUnchecked(code wasmvm.WasmCode) (wasmvm.Checksum, error) // AnalyzeCode will statically analyze the code. @@ -49,7 +52,7 @@ type WasmEngine interface { gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction, - ) (*wasmvmtypes.Response, uint64, error) + ) (*wasmvmtypes.ContractResult, uint64, error) // Execute calls a given contract. Since the only difference between contracts with the same CodeID is the // data in their local storage, and their address in the outside world, we need no ContractID here. @@ -68,7 +71,7 @@ type WasmEngine interface { gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction, - ) (*wasmvmtypes.Response, uint64, error) + ) (*wasmvmtypes.ContractResult, uint64, error) // Query allows a client to execute a contract-specific query. If the result is not empty, it should be // valid json-encoded data to return to the client. @@ -83,7 +86,7 @@ type WasmEngine interface { gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction, - ) ([]byte, uint64, error) + ) (*types.QueryResult, uint64, error) // Migrate will migrate an existing contract to a new code binary. // This takes storage of the data from the original contract and the CodeID of the new contract that should @@ -101,7 +104,7 @@ type WasmEngine interface { gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction, - ) (*wasmvmtypes.Response, uint64, error) + ) (*wasmvmtypes.ContractResult, uint64, error) // Sudo runs an existing contract in read/write mode (like Execute), but is never exposed to external callers // (either transactions or government proposals), but can only be called by other native Go modules directly. @@ -118,7 +121,7 @@ type WasmEngine interface { gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction, - ) (*wasmvmtypes.Response, uint64, error) + ) (*wasmvmtypes.ContractResult, uint64, error) // Reply is called on the original dispatching contract after running a submessage Reply( @@ -131,7 +134,7 @@ type WasmEngine interface { gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction, - ) (*wasmvmtypes.Response, uint64, error) + ) (*wasmvmtypes.ContractResult, uint64, error) // GetCode will load the original wasm code for the given code id. // This will only succeed if that code id was previously returned from @@ -157,7 +160,7 @@ type WasmEngine interface { gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction, - ) (*wasmvmtypes.IBC3ChannelOpenResponse, uint64, error) + ) (*wasmvmtypes.IBCChannelOpenResult, uint64, error) // IBCChannelConnect is available on IBC-enabled contracts and is a hook to call into // during the handshake phase @@ -171,7 +174,7 @@ type WasmEngine interface { gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction, - ) (*wasmvmtypes.IBCBasicResponse, uint64, error) + ) (*wasmvmtypes.IBCBasicResult, uint64, error) // IBCChannelClose is available on IBC-enabled contracts and is a hook to call into // at the end of the channel lifetime @@ -185,7 +188,7 @@ type WasmEngine interface { gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction, - ) (*wasmvmtypes.IBCBasicResponse, uint64, error) + ) (*wasmvmtypes.IBCBasicResult, uint64, error) // IBCPacketReceive is available on IBC-enabled contracts and is called when an incoming // packet is received on a channel belonging to this contract @@ -214,7 +217,7 @@ type WasmEngine interface { gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction, - ) (*wasmvmtypes.IBCBasicResponse, uint64, error) + ) (*wasmvmtypes.IBCBasicResult, uint64, error) // IBCPacketTimeout is available on IBC-enabled contracts and is called when an // outgoing packet (previously sent by this contract) will probably never be executed. @@ -229,7 +232,7 @@ type WasmEngine interface { gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction, - ) (*wasmvmtypes.IBCBasicResponse, uint64, error) + ) (*wasmvmtypes.IBCBasicResult, uint64, error) // Pin pins a code to an in-memory cache, such that is // always loaded quickly when executed. From e4d95c24535ce750830a0d71f790422fd6841fe2 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Wed, 7 Feb 2024 16:19:25 +0100 Subject: [PATCH 04/45] Fix StoreCode gas usage --- x/wasm/keeper/keeper.go | 5 ++- x/wasm/keeper/wasmtesting/gas_register.go | 8 ----- x/wasm/keeper/wasmtesting/mock_engine.go | 4 +-- x/wasm/types/gas_register.go | 10 ------ x/wasm/types/gas_register_test.go | 37 ----------------------- 5 files changed, 4 insertions(+), 60 deletions(-) diff --git a/x/wasm/keeper/keeper.go b/x/wasm/keeper/keeper.go index c169c043df..9524bd8c03 100644 --- a/x/wasm/keeper/keeper.go +++ b/x/wasm/keeper/keeper.go @@ -168,9 +168,8 @@ func (k Keeper) create(ctx context.Context, creator sdk.AccAddress, wasmCode []b } } - sdkCtx.GasMeter().ConsumeGas(k.gasRegister.CompileCosts(len(wasmCode)), "Compiling wasm bytecode") - gas := k.runtimeGasForContract(sdkCtx) - checksum, gasUsed, err := k.wasmVM.StoreCode(wasmCode, gas) + gasLeft := k.runtimeGasForContract(sdkCtx) + checksum, gasUsed, err := k.wasmVM.StoreCode(wasmCode, gasLeft) k.consumeRuntimeGas(sdkCtx, gasUsed) if err != nil { return 0, checksum, errorsmod.Wrap(types.ErrCreateFailed, err.Error()) diff --git a/x/wasm/keeper/wasmtesting/gas_register.go b/x/wasm/keeper/wasmtesting/gas_register.go index 77c176e4ea..a16de3b32d 100644 --- a/x/wasm/keeper/wasmtesting/gas_register.go +++ b/x/wasm/keeper/wasmtesting/gas_register.go @@ -8,7 +8,6 @@ import ( // MockGasRegister mock that implements keeper.GasRegister type MockGasRegister struct { - CompileCostFn func(byteLength int) storetypes.Gas SetupContractCostFn func(discount bool, msgLen int) storetypes.Gas ReplyCostFn func(discount bool, reply wasmvmtypes.Reply) storetypes.Gas EventCostsFn func(evts []wasmvmtypes.EventAttribute) storetypes.Gas @@ -17,13 +16,6 @@ type MockGasRegister struct { UncompressCostsFn func(byteLength int) storetypes.Gas } -func (m MockGasRegister) CompileCosts(byteLength int) storetypes.Gas { - if m.CompileCostFn == nil { - panic("not expected to be called") - } - return m.CompileCostFn(byteLength) -} - func (m MockGasRegister) UncompressCosts(byteLength int) storetypes.Gas { if m.UncompressCostsFn == nil { panic("not expected to be called") diff --git a/x/wasm/keeper/wasmtesting/mock_engine.go b/x/wasm/keeper/wasmtesting/mock_engine.go index 1b3465bfae..9ef1c583a2 100644 --- a/x/wasm/keeper/wasmtesting/mock_engine.go +++ b/x/wasm/keeper/wasmtesting/mock_engine.go @@ -348,8 +348,8 @@ func NoOpInstantiateFn(wasmvm.Checksum, wasmvmtypes.Env, wasmvmtypes.MessageInfo return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{}}, 0, nil } -func NoOpStoreCodeFn(_ wasmvm.WasmCode) (wasmvm.Checksum, error) { - return rand.Bytes(32), nil +func NoOpStoreCodeFn(wasm wasmvm.WasmCode, gasLimit uint64) (wasmvm.Checksum, uint64, error) { + return rand.Bytes(32), uint64(MockStoreCodeCostPerByte * len(wasm)), nil } func HasIBCAnalyzeFn(wasmvm.Checksum) (*wasmvmtypes.AnalysisReport, error) { diff --git a/x/wasm/types/gas_register.go b/x/wasm/types/gas_register.go index 15e9058b1e..c7617b6557 100644 --- a/x/wasm/types/gas_register.go +++ b/x/wasm/types/gas_register.go @@ -74,8 +74,6 @@ func DefaultPerByteUncompressCost() wasmvmtypes.UFraction { // GasRegister abstract source for gas costs type GasRegister interface { - // CompileCosts costs to persist and "compile" a new wasm contract - CompileCosts(byteLength int) storetypes.Gas // UncompressCosts costs to unpack a new wasm contract UncompressCosts(byteLength int) storetypes.Gas // SetupContractCost are charged when interacting with a Wasm contract, i.e. every time @@ -165,14 +163,6 @@ func NewWasmGasRegister(c WasmGasRegisterConfig) WasmGasRegister { } } -// CompileCosts costs to persist and "compile" a new wasm contract -func (g WasmGasRegister) CompileCosts(byteLength int) storetypes.Gas { - if byteLength < 0 { - panic(errorsmod.Wrap(ErrInvalid, "negative length")) - } - return g.c.CompileCost * uint64(byteLength) -} - // UncompressCosts costs to unpack a new wasm contract func (g WasmGasRegister) UncompressCosts(byteLength int) storetypes.Gas { if byteLength < 0 { diff --git a/x/wasm/types/gas_register_test.go b/x/wasm/types/gas_register_test.go index d530fa02ec..45e9719cbf 100644 --- a/x/wasm/types/gas_register_test.go +++ b/x/wasm/types/gas_register_test.go @@ -11,43 +11,6 @@ import ( storetypes "cosmossdk.io/store/types" ) -func TestCompileCosts(t *testing.T) { - specs := map[string]struct { - srcLen int - srcConfig WasmGasRegisterConfig - exp storetypes.Gas - expPanic bool - }{ - "one byte": { - srcLen: 1, - srcConfig: DefaultGasRegisterConfig(), - exp: storetypes.Gas(3), // DefaultCompileCost - }, - "zero byte": { - srcLen: 0, - srcConfig: DefaultGasRegisterConfig(), - exp: storetypes.Gas(0), - }, - "negative len": { - srcLen: -1, - srcConfig: DefaultGasRegisterConfig(), - expPanic: true, - }, - } - for name, spec := range specs { - t.Run(name, func(t *testing.T) { - if spec.expPanic { - assert.Panics(t, func() { - NewWasmGasRegister(spec.srcConfig).CompileCosts(spec.srcLen) - }) - return - } - gotGas := NewWasmGasRegister(spec.srcConfig).CompileCosts(spec.srcLen) - assert.Equal(t, spec.exp, gotGas) - }) - } -} - func TestSetupContractCost(t *testing.T) { specs := map[string]struct { srcLen int From 54670c499021e240b4859afa4c4891e1a6b1d2db Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Wed, 7 Feb 2024 17:08:19 +0100 Subject: [PATCH 05/45] Add ValidateAddress impl --- x/wasm/keeper/api.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/x/wasm/keeper/api.go b/x/wasm/keeper/api.go index 8101fef246..9d3ef49183 100644 --- a/x/wasm/keeper/api.go +++ b/x/wasm/keeper/api.go @@ -14,6 +14,8 @@ const ( DefaultGasCostHumanAddress = 5 // DefaultGasCostCanonicalAddress is how much SDK gas we charge to convert to a canonical address format DefaultGasCostCanonicalAddress = 4 + // DefaultGasCostValidateAddress is how much SDK gas we charge to validate an address + DefaultGasCostValidateAddress = 4 // DefaultDeserializationCostPerByte The formula should be `len(data) * deserializationCostPerByte` DefaultDeserializationCostPerByte = 1 @@ -22,6 +24,7 @@ const ( var ( costHumanize = DefaultGasCostHumanAddress * types.DefaultGasMultiplier costCanonical = DefaultGasCostCanonicalAddress * types.DefaultGasMultiplier + costValidate = DefaultGasCostCanonicalAddress * types.DefaultGasMultiplier costJSONDeserialization = wasmvmtypes.UFraction{ Numerator: DefaultDeserializationCostPerByte * types.DefaultGasMultiplier, Denominator: 1, @@ -40,7 +43,13 @@ func canonicalizeAddress(human string) ([]byte, uint64, error) { return bz, costCanonical, err } +func validateAddress(human string) (uint64, error) { + _, err := sdk.AccAddressFromBech32(human) + return costValidate, err +} + var cosmwasmAPI = wasmvm.GoAPI{ HumanizeAddress: humanizeAddress, CanonicalizeAddress: canonicalizeAddress, + ValidateAddress: validateAddress, } From 73e7ebb4d6715d6e3cdb69fa3c5dfd9db9bcc0f2 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Wed, 7 Feb 2024 17:09:14 +0100 Subject: [PATCH 06/45] go mod tidy --- go.sum | 4 ---- 1 file changed, 4 deletions(-) diff --git a/go.sum b/go.sum index 91de6928bd..5f2d7fc589 100644 --- a/go.sum +++ b/go.sum @@ -228,8 +228,6 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25 github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/CosmWasm/wasmvm v1.5.2 h1:+pKB1Mz9GZVt1vadxB+EDdD1FOz3dMNjIKq/58/lrag= -github.com/CosmWasm/wasmvm v1.5.2/go.mod h1:Q0bSEtlktzh7W2hhEaifrFp1Erx11ckQZmjq8FLCyys= github.com/CosmWasm/wasmvm/v2 v2.0.0-rc.1 h1:svmpiJLnLX8bQfqa4ZgsAIT/ldzPCjvJPNlHJkJhAlA= github.com/CosmWasm/wasmvm/v2 v2.0.0-rc.1/go.mod h1:su9lg5qLr7adV95eOfzjZWkGiky8WNaNIHDr7Fpu7Ck= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= @@ -1342,8 +1340,6 @@ golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= From cca0005c715547d42aa66e1f0a86184763d19512 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Wed, 7 Feb 2024 17:20:08 +0100 Subject: [PATCH 07/45] Fix lint --- x/wasm/types/wasmer_engine.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/x/wasm/types/wasmer_engine.go b/x/wasm/types/wasmer_engine.go index 08d934de2b..f3829e9146 100644 --- a/x/wasm/types/wasmer_engine.go +++ b/x/wasm/types/wasmer_engine.go @@ -2,7 +2,6 @@ package types import ( wasmvm "github.com/CosmWasm/wasmvm/v2" - "github.com/CosmWasm/wasmvm/v2/types" wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" storetypes "cosmossdk.io/store/types" @@ -86,7 +85,7 @@ type WasmEngine interface { gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction, - ) (*types.QueryResult, uint64, error) + ) (*wasmvmtypes.QueryResult, uint64, error) // Migrate will migrate an existing contract to a new code binary. // This takes storage of the data from the original contract and the CodeID of the new contract that should From 244c55a4bae11669cd5722cabf1570c27daaf2d8 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Wed, 7 Feb 2024 17:58:43 +0100 Subject: [PATCH 08/45] Reduce gas factor --- x/wasm/types/gas_register.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x/wasm/types/gas_register.go b/x/wasm/types/gas_register.go index c7617b6557..ca6e11c235 100644 --- a/x/wasm/types/gas_register.go +++ b/x/wasm/types/gas_register.go @@ -21,6 +21,7 @@ const ( // Rough timing have 88k gas at 90us, which is equal to 1k sdk gas... (one read)" // as well as manual Wasmer benchmarks from 2019. This was then multiplied by 150_000 // in the 0.16 -> 1.0 upgrade (https://github.com/CosmWasm/cosmwasm/pull/1120). + // In the 2.0 upgrade, this was reduced by a factor of 1000 (https://github.com/CosmWasm/cosmwasm/pull/1884). // // The multiplier deserves more reproducible benchmarking and a strategy that allows easy adjustments. // This is tracked in https://github.com/CosmWasm/wasmd/issues/566 and https://github.com/CosmWasm/wasmd/issues/631. @@ -30,7 +31,7 @@ const ( // // Please note that all gas prices returned to wasmvm should have this multiplied. // Benchmarks and numbers were discussed in: https://github.com/CosmWasm/wasmd/pull/634#issuecomment-938055852 - DefaultGasMultiplier uint64 = 140_000_000 + DefaultGasMultiplier uint64 = 140_000 // DefaultInstanceCost is how much SDK gas we charge each time we load a WASM instance. // Creating a new instance is costly, and this helps put a recursion limit to contracts calling contracts. // Benchmarks and numbers were discussed in: https://github.com/CosmWasm/wasmd/pull/634#issuecomment-938056803 From c8f84ff6008184d4a28eb6c6ea2c7fce1ae9a3bf Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Wed, 7 Feb 2024 17:59:44 +0100 Subject: [PATCH 09/45] Fix wasmvm path in CI --- .circleci/config.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 7a8fcab642..fbe4754bf7 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -97,7 +97,7 @@ jobs: - "profiles/*" - store_artifacts: path: /tmp/logs - + test-system: executor: golang parallelism: 1 @@ -189,7 +189,7 @@ jobs: command: | IN_DOCKER=$(docker run --rm "cosmwasm/wasmd:${CIRCLE_SHA1}" /usr/bin/wasmd query wasm libwasmvm-version) echo "Runtime libwasmvm-version in docker: $IN_DOCKER" - IN_GOMOD=$(go list -m github.com/CosmWasm/wasmvm | cut -d" " -f2 | cut -d"v" -f2) + IN_GOMOD=$(go list -m github.com/CosmWasm/wasmvm/v2 | cut -d" " -f2 | cut -d"v" -f2) echo "wasmvm version in go.mod: $IN_GOMOD" if [[ "$IN_DOCKER" != "$IN_GOMOD" ]]; then echo "Mismatch of wasmvm versions detected" @@ -197,7 +197,7 @@ jobs: fi - when: condition: - equal: [ main, << pipeline.git.branch >> ] + equal: [main, << pipeline.git.branch >>] steps: - run: name: Push application Docker image to docker hub From ec2c70bf72e47b25026ed52dd260213029f14a4c Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Thu, 8 Feb 2024 11:17:55 +0100 Subject: [PATCH 10/45] Fix address validation --- x/wasm/keeper/api.go | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/x/wasm/keeper/api.go b/x/wasm/keeper/api.go index 9d3ef49183..f774b042e8 100644 --- a/x/wasm/keeper/api.go +++ b/x/wasm/keeper/api.go @@ -1,6 +1,8 @@ package keeper import ( + "errors" + wasmvm "github.com/CosmWasm/wasmvm/v2" wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" @@ -15,7 +17,7 @@ const ( // DefaultGasCostCanonicalAddress is how much SDK gas we charge to convert to a canonical address format DefaultGasCostCanonicalAddress = 4 // DefaultGasCostValidateAddress is how much SDK gas we charge to validate an address - DefaultGasCostValidateAddress = 4 + DefaultGasCostValidateAddress = 9 // DefaultDeserializationCostPerByte The formula should be `len(data) * deserializationCostPerByte` DefaultDeserializationCostPerByte = 1 @@ -44,7 +46,14 @@ func canonicalizeAddress(human string) ([]byte, uint64, error) { } func validateAddress(human string) (uint64, error) { - _, err := sdk.AccAddressFromBech32(human) + canonicalized, err := sdk.AccAddressFromBech32(human) + if err != nil { + return costValidate, err + } + // AccAddressFromBech32 already calls VerifyAddressFormat, so we can just humanize and compare + if sdk.AccAddress(canonicalized).String() != human { + return costValidate, errors.New("address not normalized") + } return costValidate, err } From ffe6aaa5ec7aecab6798264f6069cf53e0a69be0 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Thu, 8 Feb 2024 11:58:34 +0100 Subject: [PATCH 11/45] Fix dockerfile --- Dockerfile | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/Dockerfile b/Dockerfile index 83131b6629..e7e59e7d80 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,13 +15,10 @@ RUN apk add git WORKDIR /code COPY . /code/ # See https://github.com/CosmWasm/wasmvm/releases -ADD https://github.com/CosmWasm/wasmvm/releases/download/v1.5.2/libwasmvm_muslc.aarch64.a /lib/libwasmvm_muslc.aarch64.a -ADD https://github.com/CosmWasm/wasmvm/releases/download/v1.5.2/libwasmvm_muslc.x86_64.a /lib/libwasmvm_muslc.x86_64.a -RUN sha256sum /lib/libwasmvm_muslc.aarch64.a | grep e78b224c15964817a3b75a40e59882b4d0e06fd055b39514d61646689cef8c6e -RUN sha256sum /lib/libwasmvm_muslc.x86_64.a | grep e660a38efb2930b34ee6f6b0bb12730adccb040b6ab701b8f82f34453a426ae7 - -# Copy the library you want to the final location that will be found by the linker flag `-lwasmvm_muslc` -RUN cp /lib/libwasmvm_muslc.${arch}.a /lib/libwasmvm_muslc.a +ADD https://github.com/CosmWasm/wasmvm/releases/download/v2.0.0-rc.1/libwasmvm_muslc.aarch64.a /lib/libwasmvm_muslc.aarch64.a +ADD https://github.com/CosmWasm/wasmvm/releases/download/v2.0.0-rc.1/libwasmvm_muslc.x86_64.a /lib/libwasmvm_muslc.x86_64.a +RUN sha256sum /lib/libwasmvm_muslc.aarch64.a | grep e3418ecdbff156fb02d4dd6e44a6c3e1d5128f28848b397712ce0a5064626222 +RUN sha256sum /lib/libwasmvm_muslc.x86_64.a | grep 9be6d5383865daf233a414c4cb739239c31fd6a68b42decce90ebab31ad291c6 # force it to use static lib (from above) not standard libgo_cosmwasm.so file RUN LEDGER_ENABLED=false BUILD_TAGS=muslc LINK_STATICALLY=true make build From db25a8284a8a02b6fc336e1ad3b0d65528511269 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Thu, 8 Feb 2024 13:23:03 +0100 Subject: [PATCH 12/45] Add cosmwasm_2_0 capability --- app/wasm.go | 1 + 1 file changed, 1 insertion(+) diff --git a/app/wasm.go b/app/wasm.go index 70f811bc18..9c9d4cb69e 100644 --- a/app/wasm.go +++ b/app/wasm.go @@ -12,5 +12,6 @@ func AllCapabilities() []string { "cosmwasm_1_2", "cosmwasm_1_3", "cosmwasm_1_4", + "cosmwasm_2_0", } } From dd992b0deb9d1220273339d34a143b760bf61888 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Wed, 14 Feb 2024 16:39:31 +0100 Subject: [PATCH 13/45] Use different tempdir for each test run --- x/wasm/keeper/options_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x/wasm/keeper/options_test.go b/x/wasm/keeper/options_test.go index 96ad46d205..1ac311c14c 100644 --- a/x/wasm/keeper/options_test.go +++ b/x/wasm/keeper/options_test.go @@ -143,10 +143,11 @@ func TestConstructorOptions(t *testing.T) { } for name, spec := range specs { t.Run(name, func(t *testing.T) { + tempDir := t.TempDir() opt := spec.srcOpt _, gotPostOptMarker := opt.(postOptsFn) require.Equal(t, spec.isPostOpt, gotPostOptMarker) - k := NewKeeper(codec, runtime.NewKVStoreService(storeKey), authkeeper.AccountKeeper{}, &bankkeeper.BaseKeeper{}, stakingkeeper.Keeper{}, nil, nil, nil, nil, nil, nil, nil, nil, "tempDir", types.DefaultWasmConfig(), AvailableCapabilities, "", spec.srcOpt) + k := NewKeeper(codec, runtime.NewKVStoreService(storeKey), authkeeper.AccountKeeper{}, &bankkeeper.BaseKeeper{}, stakingkeeper.Keeper{}, nil, nil, nil, nil, nil, nil, nil, nil, tempDir, types.DefaultWasmConfig(), AvailableCapabilities, "", spec.srcOpt) spec.verify(t, k) }) } From 59848968ea8ead81246bc62ceb1ab765777a54db Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Thu, 15 Feb 2024 14:31:44 +0100 Subject: [PATCH 14/45] Add cosmwasm_2_0 capability to README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index d7475a5c64..d28d405bd4 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,7 @@ The following table shows which of the [latest capabilities](https://github.com/ | cosmwasm_1_2 | x | x | x | | | | cosmwasm_1_3 | x | x | | | | | cosmwasm_1_4 | x | | | | | +| cosmwasm_2_0 | | | | | | ### For node developers From 6d7c91c145c966c0c39118bf4e1327dfe2966619 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Thu, 15 Feb 2024 14:42:07 +0100 Subject: [PATCH 15/45] Remove unnecessary conversion --- x/wasm/keeper/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/wasm/keeper/api.go b/x/wasm/keeper/api.go index f774b042e8..ed547b1fef 100644 --- a/x/wasm/keeper/api.go +++ b/x/wasm/keeper/api.go @@ -51,7 +51,7 @@ func validateAddress(human string) (uint64, error) { return costValidate, err } // AccAddressFromBech32 already calls VerifyAddressFormat, so we can just humanize and compare - if sdk.AccAddress(canonicalized).String() != human { + if canonicalized.String() != human { return costValidate, errors.New("address not normalized") } return costValidate, err From 2ec06281e600374cd51062717e11f0cd087aaa3b Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Thu, 15 Feb 2024 15:13:00 +0100 Subject: [PATCH 16/45] Fix TestAppStateDeterminism --- app/sim_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/sim_test.go b/app/sim_test.go index 94fa34e66e..f2a712cd72 100644 --- a/app/sim_test.go +++ b/app/sim_test.go @@ -318,7 +318,6 @@ func TestAppStateDeterminism(t *testing.T) { appOptions.SetDefault(key, value) } } - appOptions.SetDefault(flags.FlagHome, t.TempDir()) // ensure a unique folder appOptions.SetDefault(server.FlagInvCheckPeriod, simcli.FlagPeriodValue) for i := 0; i < numSeeds; i++ { @@ -331,6 +330,8 @@ func TestAppStateDeterminism(t *testing.T) { logger = log.NewNopLogger() } + appOptions.SetDefault(flags.FlagHome, t.TempDir()) // ensure a unique folder per run + db := dbm.NewMemDB() app := NewWasmApp(logger, db, nil, true, appOptions, emptyWasmOpts, interBlockCacheOpt(), baseapp.SetChainID(SimAppChainID)) From 137cb2680af7cf59ab25f5d574e2e557fffbbc60 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Thu, 15 Feb 2024 15:36:08 +0100 Subject: [PATCH 17/45] Fix TestAppImportExport --- app/sim_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/sim_test.go b/app/sim_test.go index f2a712cd72..c4e1cebdc0 100644 --- a/app/sim_test.go +++ b/app/sim_test.go @@ -123,6 +123,8 @@ func TestAppImportExport(t *testing.T) { require.NoError(t, os.RemoveAll(newDir)) }() + appOptions[flags.FlagHome] = t.TempDir() // ensure a unique folder for the new app + newApp := NewWasmApp(log.NewNopLogger(), newDB, nil, true, appOptions, emptyWasmOpts, fauxMerkleModeOpt, baseapp.SetChainID(SimAppChainID)) require.Equal(t, "WasmApp", newApp.Name()) From 1d77a666e66f94625c236b8e819c40fa8e4d76e7 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Thu, 15 Feb 2024 16:45:20 +0100 Subject: [PATCH 18/45] Fix errors --- x/wasm/keeper/keeper.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x/wasm/keeper/keeper.go b/x/wasm/keeper/keeper.go index 9524bd8c03..3b833b0051 100644 --- a/x/wasm/keeper/keeper.go +++ b/x/wasm/keeper/keeper.go @@ -550,7 +550,7 @@ func (k Keeper) Sudo(ctx context.Context, contractAddress sdk.AccAddress, msg [] return nil, errorsmod.Wrap(types.ErrExecuteFailed, execErr.Error()) } if res.Err != "" { - return nil, errorsmod.Wrap(types.ErrMigrationFailed, res.Err) + return nil, errorsmod.Wrap(types.ErrExecuteFailed, res.Err) } sdkCtx.EventManager().EmitEvent(sdk.NewEvent( @@ -590,7 +590,7 @@ func (k Keeper) reply(ctx sdk.Context, contractAddress sdk.AccAddress, reply was return nil, errorsmod.Wrap(types.ErrExecuteFailed, execErr.Error()) } if res.Err != "" { - return nil, errorsmod.Wrap(types.ErrMigrationFailed, res.Err) + return nil, errorsmod.Wrap(types.ErrExecuteFailed, res.Err) } ctx.EventManager().EmitEvent(sdk.NewEvent( @@ -776,7 +776,7 @@ func (k Keeper) QuerySmart(ctx context.Context, contractAddr sdk.AccAddress, req return nil, errorsmod.Wrap(types.ErrQueryFailed, qErr.Error()) } if queryResult.Err != "" { - return nil, errorsmod.Wrap(types.ErrMigrationFailed, queryResult.Err) + return nil, errorsmod.Wrap(types.ErrQueryFailed, queryResult.Err) } return queryResult.Ok, nil } From 1037fc8f9ec5b4fe539f9ba49bbfcd8cabc6db4d Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Thu, 15 Feb 2024 17:13:58 +0100 Subject: [PATCH 19/45] Use updated reflect contract --- tests/e2e/group_test.go | 57 +++++++++++++++++- tests/e2e/reflect_helper.go | 41 ++++++++++++- x/wasm/keeper/keeper_test.go | 8 +-- .../keeper/query_plugin_integration_test.go | 2 +- x/wasm/keeper/reflect_test.go | 2 +- x/wasm/keeper/testdata/contracts.go | 2 +- x/wasm/keeper/testdata/reflect_2_0.wasm | Bin 0 -> 380600 bytes x/wasm/module_test.go | 2 +- 8 files changed, 103 insertions(+), 11 deletions(-) create mode 100644 x/wasm/keeper/testdata/reflect_2_0.wasm diff --git a/tests/e2e/group_test.go b/tests/e2e/group_test.go index 9852d9793a..2cda127a74 100644 --- a/tests/e2e/group_test.go +++ b/tests/e2e/group_test.go @@ -27,7 +27,7 @@ func TestGroupWithContract(t *testing.T) { coord := ibctesting.NewCoordinator(t, 1) chain := coord.GetChain(ibctesting.GetChainID(1)) - contractAddr := e2e.InstantiateReflectContract(t, chain) + contractAddr := e2e.InstantiateStargateReflectContract(t, chain) chain.Fund(contractAddr, sdkmath.NewIntFromUint64(1_000_000_000)) members := []group.MemberRequest{ @@ -74,3 +74,58 @@ func TestGroupWithContract(t *testing.T) { expBalanceAmount := sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.OneInt()) assert.Equal(t, expBalanceAmount.String(), recipientBalance.String()) } + +func TestGroupWithNewReflectContract(t *testing.T) { + // Given a group with a contract as only member + // When contract submits a proposal with try_execute + // Then the payload msg is executed + + coord := ibctesting.NewCoordinator(t, 1) + chain := coord.GetChain(ibctesting.GetChainID(1)) + contractAddr := e2e.InstantiateReflectContract(t, chain) + chain.Fund(contractAddr, sdkmath.NewIntFromUint64(1_000_000_000)) + + members := []group.MemberRequest{ + { + Address: contractAddr.String(), + Weight: "1", + Metadata: "my contract", + }, + } + msg, err := group.NewMsgCreateGroupWithPolicy( + chain.SenderAccount.GetAddress().String(), + members, + "my group", + "my metadata", + false, + group.NewPercentageDecisionPolicy("1", time.Second, 0), + ) + require.NoError(t, err) + rsp, err := chain.SendMsgs(msg) + require.NoError(t, err) + + var createRsp group.MsgCreateGroupWithPolicyResponse + chain.UnwrapExecTXResult(rsp, &createRsp) + groupID, policyAddr := createRsp.GroupId, sdk.MustAccAddressFromBech32(createRsp.GroupPolicyAddress) + require.NotEmpty(t, groupID) + chain.Fund(policyAddr, sdkmath.NewIntFromUint64(1_000_000_000)) + // and a proposal submitted + recipientAddr := sdk.AccAddress(rand.Bytes(address.Len)) + + payload := []sdk.Msg{banktypes.NewMsgSend(policyAddr, recipientAddr, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.OneInt())))} + propMsg, err := group.NewMsgSubmitProposal(policyAddr.String(), []string{contractAddr.String()}, payload, "my proposal", group.Exec_EXEC_TRY, "my title", "my description") + require.NoError(t, err) + + rsp = e2e.MustExecViaAnyReflectContract(t, chain, contractAddr, propMsg) + var execRsp types.MsgExecuteContractResponse + chain.UnwrapExecTXResult(rsp, &execRsp) + + var groupRsp group.MsgSubmitProposalResponse + require.NoError(t, chain.Codec.Unmarshal(execRsp.Data, &groupRsp)) + // require.NotEmpty(t, groupRsp.ProposalId) + + // and coins received + recipientBalance := chain.Balance(recipientAddr, sdk.DefaultBondDenom) + expBalanceAmount := sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.OneInt()) + assert.Equal(t, expBalanceAmount.String(), recipientBalance.String()) +} diff --git a/tests/e2e/reflect_helper.go b/tests/e2e/reflect_helper.go index e64d8bf139..44235eab3b 100644 --- a/tests/e2e/reflect_helper.go +++ b/tests/e2e/reflect_helper.go @@ -1,7 +1,9 @@ package e2e import ( + "encoding/base64" "encoding/json" + "fmt" "testing" wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" @@ -16,9 +18,18 @@ import ( "github.com/CosmWasm/wasmd/x/wasm/types" ) -// InstantiateReflectContract store and instantiate a reflect contract instance +// InstantiateStargateReflectContract stores and instantiates a pre 2.0 reflect contract instance. +// This instance still expects the old CosmosMsg.Stargate variant instead of the new CosmosMsg.Any. +func InstantiateStargateReflectContract(t *testing.T, chain *ibctesting.TestChain) sdk.AccAddress { + codeID := chain.StoreCodeFile("../../x/wasm/keeper/testdata/reflect.wasm").CodeID + contractAddr := chain.InstantiateContract(codeID, []byte(`{}`)) + require.NotEmpty(t, contractAddr) + return contractAddr +} + +// InstantiateReflectContract stores and instantiates a 2.0 reflect contract instance. func InstantiateReflectContract(t *testing.T, chain *ibctesting.TestChain) sdk.AccAddress { - codeID := chain.StoreCodeFile("../../x/wasm/keeper/testdata/reflect_1_1.wasm").CodeID + codeID := chain.StoreCodeFile("../../x/wasm/keeper/testdata/reflect_2_0.wasm").CodeID contractAddr := chain.InstantiateContract(codeID, []byte(`{}`)) require.NotEmpty(t, contractAddr) return contractAddr @@ -37,6 +48,32 @@ type sdkMessageType interface { } func MustExecViaStargateReflectContract[T sdkMessageType](t *testing.T, chain *ibctesting.TestChain, contractAddr sdk.AccAddress, msgs ...T) *abci.ExecTxResult { + require.NotEmpty(t, msgs) + // convert messages to stargate variant + vmMsgs := make([]string, len(msgs)) + for i, m := range msgs { + bz, err := chain.Codec.Marshal(m) + require.NoError(t, err) + // json is built manually because the wasmvm CosmosMsg does not have the `Stargate` variant anymore + vmMsgs[i] = fmt.Sprintf("{\"stargate\":{\"type_url\":\"%s\",\"value\":\"%s\"}}", sdk.MsgTypeURL(m), base64.StdEncoding.EncodeToString(bz)) + } + // build the complete reflect message + reflectSendBz := []byte(fmt.Sprintf("{\"reflect_msg\":{\"msgs\":%s}}", vmMsgs)) + + // {"reflect_msg":{"msgs":[{"stargate":{"type_url":"mytype","value":"EjQ="}}]}} + + t.Log(string(reflectSendBz)) + execMsg := &types.MsgExecuteContract{ + Sender: chain.SenderAccount.GetAddress().String(), + Contract: contractAddr.String(), + Msg: reflectSendBz, + } + rsp, err := chain.SendMsgs(execMsg) + require.NoError(t, err) + return rsp +} + +func MustExecViaAnyReflectContract[T sdkMessageType](t *testing.T, chain *ibctesting.TestChain, contractAddr sdk.AccAddress, msgs ...T) *abci.ExecTxResult { vmMsgs := make([]wasmvmtypes.CosmosMsg, len(msgs)) for i, m := range msgs { bz, err := chain.Codec.Marshal(m) diff --git a/x/wasm/keeper/keeper_test.go b/x/wasm/keeper/keeper_test.go index cb7d11be10..d39554ff48 100644 --- a/x/wasm/keeper/keeper_test.go +++ b/x/wasm/keeper/keeper_test.go @@ -44,7 +44,7 @@ import ( var hackatomWasm []byte var AvailableCapabilities = []string{ - "iterator", "staking", "stargate", "cosmwasm_1_1", "cosmwasm_1_2", "cosmwasm_1_3", "cosmwasm_1_4", + "iterator", "staking", "stargate", "cosmwasm_1_1", "cosmwasm_1_2", "cosmwasm_1_3", "cosmwasm_1_4", "cosmwasm_2_0", } func TestNewKeeper(t *testing.T) { @@ -421,7 +421,7 @@ func TestInstantiate(t *testing.T) { gasAfter := ctx.GasMeter().GasConsumed() if types.EnableGasVerification { - require.Equal(t, uint64(0x1bc64), gasAfter-gasBefore) + require.Equal(t, uint64(0x1bc5a), gasAfter-gasBefore) } // ensure it is stored properly @@ -2459,13 +2459,13 @@ func TestGasConsumed(t *testing.T) { originalMeter: storetypes.NewGasMeter(100), gasRegister: types.NewWasmGasRegister(types.DefaultGasRegisterConfig()), consumeGas: storetypes.Gas(1), - expMultipliedGasConsumed: 140000000, + expMultipliedGasConsumed: 140000, }, "consumeGas = limit": { originalMeter: storetypes.NewGasMeter(1), gasRegister: types.NewWasmGasRegister(types.DefaultGasRegisterConfig()), consumeGas: storetypes.Gas(1), - expMultipliedGasConsumed: 140000000, + expMultipliedGasConsumed: 140000, }, "consumeGas > limit": { originalMeter: storetypes.NewGasMeter(10), diff --git a/x/wasm/keeper/query_plugin_integration_test.go b/x/wasm/keeper/query_plugin_integration_test.go index 5615e835f6..4ff5954c82 100644 --- a/x/wasm/keeper/query_plugin_integration_test.go +++ b/x/wasm/keeper/query_plugin_integration_test.go @@ -794,7 +794,7 @@ func TestIBCListChannelsQuery(t *testing.T) { query: &wasmvmtypes.IBCQuery{ListChannels: &wasmvmtypes.ListChannelsQuery{}}, assert: func(t *testing.T, d []byte) { rsp := unmarshalReflect[wasmvmtypes.ListChannelsResponse](t, d) - assert.Nil(t, rsp.Channels) + assert.Empty(t, rsp.Channels) }, }, "no matching channels": { diff --git a/x/wasm/keeper/reflect_test.go b/x/wasm/keeper/reflect_test.go index 24581f2806..edb338b918 100644 --- a/x/wasm/keeper/reflect_test.go +++ b/x/wasm/keeper/reflect_test.go @@ -25,7 +25,7 @@ import ( var ( CyberpunkCapabilities = []string{"staking", "mask", "stargate", "cosmwasm_1_1", "cosmwasm_1_2", "cosmwasm_1_3", "cosmwasm_1_4"} - ReflectCapabilities = CyberpunkCapabilities + ReflectCapabilities = []string{"staking", "mask", "stargate", "cosmwasm_1_1", "cosmwasm_1_2", "cosmwasm_1_3", "cosmwasm_1_4", "cosmwasm_2_0"} ) func mustUnmarshal(t *testing.T, data []byte, res interface{}) { diff --git a/x/wasm/keeper/testdata/contracts.go b/x/wasm/keeper/testdata/contracts.go index fe587a091d..eb63bdeef6 100644 --- a/x/wasm/keeper/testdata/contracts.go +++ b/x/wasm/keeper/testdata/contracts.go @@ -13,7 +13,7 @@ const ( ) var ( - //go:embed reflect.wasm + //go:embed reflect_2_0.wasm reflectContract []byte //go:embed reflect_1_1.wasm migrateReflectContract []byte diff --git a/x/wasm/keeper/testdata/reflect_2_0.wasm b/x/wasm/keeper/testdata/reflect_2_0.wasm new file mode 100644 index 0000000000000000000000000000000000000000..9791208ace3cb3b6c94f0f588e2fae8fb9cd6c26 GIT binary patch literal 380600 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

Q}H3AaSN5nsd~ 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 literal 0 HcmV?d00001 diff --git a/x/wasm/module_test.go b/x/wasm/module_test.go index 63e8f5cd90..d75838a2a5 100644 --- a/x/wasm/module_test.go +++ b/x/wasm/module_test.go @@ -63,7 +63,7 @@ func setupTest(t *testing.T) testData { InstantiateDefaultPermission: v2.AccessTypeEverybody, } - ctx, keepers := keeper.CreateTestInput(t, false, []string{"iterator", "staking", "stargate", "cosmwasm_1_1", "cosmwasm_1_2", "cosmwasm_1_3", "cosmwasm_1_4"}) + ctx, keepers := keeper.CreateTestInput(t, false, []string{"iterator", "staking", "stargate", "cosmwasm_1_1", "cosmwasm_1_2", "cosmwasm_1_3", "cosmwasm_1_4", "cosmwasm_2_0"}) encConf := keeper.MakeEncodingConfig(t) queryRouter := baseapp.NewGRPCQueryRouter() serviceRouter := baseapp.NewMsgServiceRouter() From 5e2d766b64046691a57af2c572468f088aa68a95 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Fri, 16 Feb 2024 14:29:36 +0100 Subject: [PATCH 20/45] Update to wasmvm rc.2 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index a9f9b096e0..4e5f8824c3 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/CosmWasm/wasmd go 1.21 require ( - github.com/CosmWasm/wasmvm/v2 v2.0.0-rc.1 + github.com/CosmWasm/wasmvm/v2 v2.0.0-rc.2 github.com/cosmos/cosmos-proto v1.0.0-beta.3 github.com/cosmos/cosmos-sdk v0.50.1 github.com/cosmos/gogogateway v1.2.0 // indirect diff --git a/go.sum b/go.sum index 5f2d7fc589..0d832a2fa2 100644 --- a/go.sum +++ b/go.sum @@ -228,8 +228,8 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25 github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/CosmWasm/wasmvm/v2 v2.0.0-rc.1 h1:svmpiJLnLX8bQfqa4ZgsAIT/ldzPCjvJPNlHJkJhAlA= -github.com/CosmWasm/wasmvm/v2 v2.0.0-rc.1/go.mod h1:su9lg5qLr7adV95eOfzjZWkGiky8WNaNIHDr7Fpu7Ck= +github.com/CosmWasm/wasmvm/v2 v2.0.0-rc.2 h1:2rAO0MpNmKHKsrX/lsyo7lLjKoGDOWwMk+40hTNVfdE= +github.com/CosmWasm/wasmvm/v2 v2.0.0-rc.2/go.mod h1:su9lg5qLr7adV95eOfzjZWkGiky8WNaNIHDr7Fpu7Ck= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ= github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= From 3539fe9968e1f01c34990354553448ec70c391bb Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Fri, 16 Feb 2024 14:29:44 +0100 Subject: [PATCH 21/45] Fix gas numbers --- x/wasm/keeper/submsg_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/x/wasm/keeper/submsg_test.go b/x/wasm/keeper/submsg_test.go index 75d1519b52..016e4a92ae 100644 --- a/x/wasm/keeper/submsg_test.go +++ b/x/wasm/keeper/submsg_test.go @@ -243,7 +243,7 @@ func TestDispatchSubMsgErrorHandling(t *testing.T) { "send tokens": { submsgID: 5, msg: validBankSend, - resultAssertions: []assertion{assertReturnedEvents(0), assertGasUsed(107_000, 108_000)}, + resultAssertions: []assertion{assertReturnedEvents(0), assertGasUsed(107_000, 110_000)}, }, "not enough tokens": { submsgID: 6, @@ -263,7 +263,7 @@ func TestDispatchSubMsgErrorHandling(t *testing.T) { msg: validBankSend, gasLimit: &subGasLimit, // uses same gas as call without limit (note we do not charge the 40k on reply) - resultAssertions: []assertion{assertReturnedEvents(0), assertGasUsed(107_000, 108_000)}, + resultAssertions: []assertion{assertReturnedEvents(0), assertGasUsed(107_000, 110_000)}, }, "not enough tokens with limit": { submsgID: 16, @@ -271,7 +271,7 @@ func TestDispatchSubMsgErrorHandling(t *testing.T) { subMsgError: true, gasLimit: &subGasLimit, // uses same gas as call without limit (note we do not charge the 40k on reply) - resultAssertions: []assertion{assertGasUsed(79_700, 79_800), assertErrorString("codespace: sdk, code: 5")}, + resultAssertions: []assertion{assertGasUsed(78_000, 81_000), assertErrorString("codespace: sdk, code: 5")}, }, "out of gas caught with gas limit": { submsgID: 17, @@ -279,7 +279,7 @@ func TestDispatchSubMsgErrorHandling(t *testing.T) { subMsgError: true, gasLimit: &subGasLimit, // uses all the subGasLimit, plus the 52k or so for the main contract - resultAssertions: []assertion{assertGasUsed(subGasLimit+75_000, subGasLimit+76_000), assertErrorString("codespace: sdk, code: 11")}, + resultAssertions: []assertion{assertGasUsed(subGasLimit+75_000, subGasLimit+77_000), assertErrorString("codespace: sdk, code: 11")}, }, "instantiate contract gets address in data and events": { submsgID: 21, From b88f84ae97c10f19213709ccc7f69c3182234e67 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Fri, 16 Feb 2024 15:03:36 +0100 Subject: [PATCH 22/45] Fix Dockerfile --- Dockerfile | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index e7e59e7d80..e5da4e7c73 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,10 +15,10 @@ RUN apk add git WORKDIR /code COPY . /code/ # See https://github.com/CosmWasm/wasmvm/releases -ADD https://github.com/CosmWasm/wasmvm/releases/download/v2.0.0-rc.1/libwasmvm_muslc.aarch64.a /lib/libwasmvm_muslc.aarch64.a -ADD https://github.com/CosmWasm/wasmvm/releases/download/v2.0.0-rc.1/libwasmvm_muslc.x86_64.a /lib/libwasmvm_muslc.x86_64.a -RUN sha256sum /lib/libwasmvm_muslc.aarch64.a | grep e3418ecdbff156fb02d4dd6e44a6c3e1d5128f28848b397712ce0a5064626222 -RUN sha256sum /lib/libwasmvm_muslc.x86_64.a | grep 9be6d5383865daf233a414c4cb739239c31fd6a68b42decce90ebab31ad291c6 +ADD https://github.com/CosmWasm/wasmvm/releases/download/v2.0.0-rc.2/libwasmvm_muslc.aarch64.a /lib/libwasmvm_muslc.aarch64.a +ADD https://github.com/CosmWasm/wasmvm/releases/download/v2.0.0-rc.2/libwasmvm_muslc.x86_64.a /lib/libwasmvm_muslc.x86_64.a +RUN sha256sum /lib/libwasmvm_muslc.aarch64.a | grep 6101550283308b4a57694faf558e47ec171c763321157825b48114e9d5a14bd2 +RUN sha256sum /lib/libwasmvm_muslc.x86_64.a | grep ec20d6df9c69a0fad61d224648a262d78996f7eb43afaf4775a30064148466b6 # force it to use static lib (from above) not standard libgo_cosmwasm.so file RUN LEDGER_ENABLED=false BUILD_TAGS=muslc LINK_STATICALLY=true make build @@ -42,4 +42,4 @@ EXPOSE 26656 # tendermint rpc EXPOSE 26657 -CMD ["/usr/bin/wasmd", "version"] \ No newline at end of file +CMD ["/usr/bin/wasmd", "version"] From 288710581420dcd8e1fc8626302c4bd4b5f94c3b Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Fri, 16 Feb 2024 15:37:38 +0100 Subject: [PATCH 23/45] Handle TransferMsg.Memo field --- x/wasm/keeper/handler_plugin_encoders.go | 1 + x/wasm/keeper/handler_plugin_encoders_test.go | 78 ++++++++++++++++++- 2 files changed, 75 insertions(+), 4 deletions(-) diff --git a/x/wasm/keeper/handler_plugin_encoders.go b/x/wasm/keeper/handler_plugin_encoders.go index 91c56580e7..5ae2313e9b 100644 --- a/x/wasm/keeper/handler_plugin_encoders.go +++ b/x/wasm/keeper/handler_plugin_encoders.go @@ -317,6 +317,7 @@ func EncodeIBCMsg(portSource types.ICS20TransferPortSource) func(ctx sdk.Context Receiver: msg.Transfer.ToAddress, TimeoutHeight: ConvertWasmIBCTimeoutHeightToCosmosHeight(msg.Transfer.Timeout.Block), TimeoutTimestamp: msg.Transfer.Timeout.Timestamp, + Memo: msg.Transfer.Memo, } return []sdk.Msg{msg}, nil default: diff --git a/x/wasm/keeper/handler_plugin_encoders_test.go b/x/wasm/keeper/handler_plugin_encoders_test.go index 9d29947b54..2fa633018d 100644 --- a/x/wasm/keeper/handler_plugin_encoders_test.go +++ b/x/wasm/keeper/handler_plugin_encoders_test.go @@ -56,10 +56,8 @@ func TestEncoding(t *testing.T) { require.NoError(t, err) cases := map[string]struct { - sender sdk.AccAddress - srcMsg wasmvmtypes.CosmosMsg - srcContractIBCPort string - transferPortSource types.ICS20TransferPortSource + sender sdk.AccAddress + srcMsg wasmvmtypes.CosmosMsg // set if valid output []sdk.Msg // set if expect mapping fails @@ -428,6 +426,43 @@ func TestEncoding(t *testing.T) { }, expError: true, }, + } + encodingConfig := MakeEncodingConfig(t) + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + var ctx sdk.Context + encoder := DefaultEncoders(encodingConfig.Codec, wasmtesting.MockIBCTransferKeeper{}) + res, err := encoder.Encode(ctx, tc.sender, "", tc.srcMsg) + if tc.expError { + assert.Error(t, err) + return + } + require.NoError(t, err) + assert.Equal(t, tc.output, res) + }) + } +} + +func TestEncodeIbcMsg(t *testing.T) { + var ( + addr1 = RandomAccountAddress(t) + addr2 = RandomAccountAddress(t) + ) + valAddr := make(sdk.ValAddress, types.SDKAddrLen) + valAddr[0] = 12 + valAddr2 := make(sdk.ValAddress, types.SDKAddrLen) + valAddr2[1] = 123 + + cases := map[string]struct { + sender sdk.AccAddress + srcMsg wasmvmtypes.CosmosMsg + srcContractIBCPort string + transferPortSource types.ICS20TransferPortSource + // set if valid + output []sdk.Msg + // set if expect mapping fails + expError bool + }{ "IBC transfer with block timeout": { sender: addr1, srcContractIBCPort: "myIBCPort", @@ -530,6 +565,41 @@ func TestEncoding(t *testing.T) { }, }, }, + "IBC transfer with memo": { + sender: addr1, + srcContractIBCPort: "myIBCPort", + srcMsg: wasmvmtypes.CosmosMsg{ + IBC: &wasmvmtypes.IBCMsg{ + Transfer: &wasmvmtypes.TransferMsg{ + ChannelID: "myChanID", + ToAddress: addr2.String(), + Amount: wasmvmtypes.Coin{ + Denom: "ALX", + Amount: "1", + }, + Timeout: wasmvmtypes.IBCTimeout{Timestamp: 100}, + Memo: "myMemo", + }, + }, + }, + transferPortSource: wasmtesting.MockIBCTransferKeeper{GetPortFn: func(ctx sdk.Context) string { + return "myTransferPort" + }}, + output: []sdk.Msg{ + &ibctransfertypes.MsgTransfer{ + SourcePort: "myTransferPort", + SourceChannel: "myChanID", + Token: sdk.Coin{ + Denom: "ALX", + Amount: sdkmath.NewInt(1), + }, + Sender: addr1.String(), + Receiver: addr2.String(), + TimeoutTimestamp: 100, + Memo: "myMemo", + }, + }, + }, "IBC close channel": { sender: addr1, srcContractIBCPort: "myIBCPort", From a30e083b902c97a1e92f29667d43d7d2dd5f107d Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Wed, 31 Jan 2024 12:14:24 +0100 Subject: [PATCH 24/45] Add flattened msgResponses to SubMsgResponse --- x/wasm/keeper/handler_plugin.go | 56 ++++++++++++++++++--------------- x/wasm/keeper/msg_dispatcher.go | 36 +++++++++++++++------ 2 files changed, 57 insertions(+), 35 deletions(-) diff --git a/x/wasm/keeper/handler_plugin.go b/x/wasm/keeper/handler_plugin.go index 9bfda34997..2fc1f9c276 100644 --- a/x/wasm/keeper/handler_plugin.go +++ b/x/wasm/keeper/handler_plugin.go @@ -12,6 +12,7 @@ import ( "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" @@ -66,18 +67,19 @@ func NewSDKMessageHandler(cdc codec.Codec, router MessageRouter, encoders msgEnc } } -func (h SDKMessageHandler) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { +func (h SDKMessageHandler) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { sdkMsgs, err := h.encoders.Encode(ctx, contractAddr, contractIBCPortID, msg) if err != nil { - return nil, nil, err + return nil, nil, nil, err } for _, sdkMsg := range sdkMsgs { res, err := h.handleSdkMessage(ctx, contractAddr, sdkMsg) if err != nil { - return nil, nil, err + return nil, nil, nil, err } - // append data + // append data and msgResponses data = append(data, res.Data) + msgResponses = append(msgResponses, res.MsgResponses) // append events sdkEvents := make([]sdk.Event, len(res.Events)) for i := range res.Events { @@ -141,19 +143,19 @@ func NewMessageHandlerChain(first Messenger, others ...Messenger) *MessageHandle // order to find the right one to process given message. If a handler cannot // process given message (returns ErrUnknownMsg), its result is ignored and the // next handler is executed. -func (m MessageHandlerChain) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) ([]sdk.Event, [][]byte, error) { +func (m MessageHandlerChain) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) ([]sdk.Event, [][]byte, [][]*codectypes.Any, error) { for _, h := range m.handlers { - events, data, err := h.DispatchMsg(ctx, contractAddr, contractIBCPortID, msg) + events, data, msgResponses, err := h.DispatchMsg(ctx, contractAddr, contractIBCPortID, msg) switch { case err == nil: - return events, data, nil + return events, data, msgResponses, nil case errors.Is(err, types.ErrUnknownMsg): continue default: - return events, data, err + return events, data, msgResponses, err } } - return nil, nil, errorsmod.Wrap(types.ErrUnknownMsg, "no handler found") + return nil, nil, nil, errorsmod.Wrap(types.ErrUnknownMsg, "no handler found") } // IBCRawPacketHandler handles IBC.SendPacket messages which are published to an IBC channel. @@ -173,67 +175,69 @@ func NewIBCRawPacketHandler(ics4Wrapper types.ICS4Wrapper, channelKeeper types.C } // DispatchMsg publishes a raw IBC packet onto the channel. -func (h IBCRawPacketHandler) DispatchMsg(ctx sdk.Context, _ sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) ([]sdk.Event, [][]byte, error) { +func (h IBCRawPacketHandler) DispatchMsg(ctx sdk.Context, _ sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) ([]sdk.Event, [][]byte, [][]*codectypes.Any, error) { if msg.IBC == nil || msg.IBC.SendPacket == nil { - return nil, nil, types.ErrUnknownMsg + return nil, nil, nil, types.ErrUnknownMsg } if contractIBCPortID == "" { - return nil, nil, errorsmod.Wrapf(types.ErrUnsupportedForContract, "ibc not supported") + return nil, nil, nil, errorsmod.Wrapf(types.ErrUnsupportedForContract, "ibc not supported") } contractIBCChannelID := msg.IBC.SendPacket.ChannelID if contractIBCChannelID == "" { - return nil, nil, errorsmod.Wrapf(types.ErrEmpty, "ibc channel") + return nil, nil, nil, errorsmod.Wrapf(types.ErrEmpty, "ibc channel") } channelCap, ok := h.capabilityKeeper.GetCapability(ctx, host.ChannelCapabilityPath(contractIBCPortID, contractIBCChannelID)) if !ok { - return nil, nil, errorsmod.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability") + return nil, nil, nil, errorsmod.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability") } seq, err := h.ics4Wrapper.SendPacket(ctx, channelCap, contractIBCPortID, contractIBCChannelID, ConvertWasmIBCTimeoutHeightToCosmosHeight(msg.IBC.SendPacket.Timeout.Block), msg.IBC.SendPacket.Timeout.Timestamp, msg.IBC.SendPacket.Data) if err != nil { - return nil, nil, errorsmod.Wrap(err, "channel") + return nil, nil, nil, errorsmod.Wrap(err, "channel") } moduleLogger(ctx).Debug("ibc packet set", "seq", seq) + var msgResponse [][]*codectypes.Any resp := &types.MsgIBCSendResponse{Sequence: seq} val, err := resp.Marshal() if err != nil { - return nil, nil, errorsmod.Wrap(err, "failed to marshal IBC send response") + return nil, nil, nil, errorsmod.Wrap(err, "failed to marshal IBC send response") } + // TODO: fill msgResponse - return nil, [][]byte{val}, nil + return nil, [][]byte{val}, msgResponse, nil } var _ Messenger = MessageHandlerFunc(nil) // MessageHandlerFunc is a helper to construct a function based message handler. -type MessageHandlerFunc func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) +type MessageHandlerFunc func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) // DispatchMsg delegates dispatching of provided message into the MessageHandlerFunc. -func (m MessageHandlerFunc) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { +func (m MessageHandlerFunc) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { return m(ctx, contractAddr, contractIBCPortID, msg) } // NewBurnCoinMessageHandler handles wasmvm.BurnMsg messages func NewBurnCoinMessageHandler(burner types.Burner) MessageHandlerFunc { - return func(ctx sdk.Context, contractAddr sdk.AccAddress, _ string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + return func(ctx sdk.Context, contractAddr sdk.AccAddress, _ string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { if msg.Bank != nil && msg.Bank.Burn != nil { coins, err := ConvertWasmCoinsToSdkCoins(msg.Bank.Burn.Amount) if err != nil { - return nil, nil, err + return nil, nil, nil, err } if coins.IsZero() { - return nil, nil, types.ErrEmpty.Wrap("amount") + return nil, nil, nil, types.ErrEmpty.Wrap("amount") } if err := burner.SendCoinsFromAccountToModule(ctx, contractAddr, types.ModuleName, coins); err != nil { - return nil, nil, errorsmod.Wrap(err, "transfer to module") + return nil, nil, nil, errorsmod.Wrap(err, "transfer to module") } if err := burner.BurnCoins(ctx, types.ModuleName, coins); err != nil { - return nil, nil, errorsmod.Wrap(err, "burn coins") + return nil, nil, nil, errorsmod.Wrap(err, "burn coins") } moduleLogger(ctx).Info("Burned", "amount", coins) - return nil, nil, nil + return nil, nil, nil, nil } - return nil, nil, types.ErrUnknownMsg + return nil, nil, nil, types.ErrUnknownMsg } } diff --git a/x/wasm/keeper/msg_dispatcher.go b/x/wasm/keeper/msg_dispatcher.go index 5ab93e4520..4344f9f898 100644 --- a/x/wasm/keeper/msg_dispatcher.go +++ b/x/wasm/keeper/msg_dispatcher.go @@ -11,6 +11,7 @@ import ( errorsmod "cosmossdk.io/errors" storetypes "cosmossdk.io/store/types" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" @@ -20,7 +21,7 @@ import ( // Messenger is an extension point for custom wasmd message handling type Messenger interface { // DispatchMsg encodes the wasmVM message and dispatches it. - DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) + DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) } // replyer is a subset of keeper that can handle replies to submessages @@ -42,7 +43,7 @@ func NewMessageDispatcher(messenger Messenger, keeper replyer) *MessageDispatche // DispatchMessages sends all messages. func (d MessageDispatcher) DispatchMessages(ctx sdk.Context, contractAddr sdk.AccAddress, ibcPort string, msgs []wasmvmtypes.CosmosMsg) error { for _, msg := range msgs { - events, _, err := d.messenger.DispatchMsg(ctx, contractAddr, ibcPort, msg) + events, _, _, err := d.messenger.DispatchMsg(ctx, contractAddr, ibcPort, msg) if err != nil { return err } @@ -53,7 +54,7 @@ func (d MessageDispatcher) DispatchMessages(ctx sdk.Context, contractAddr sdk.Ac } // dispatchMsgWithGasLimit sends a message with gas limit applied -func (d MessageDispatcher) dispatchMsgWithGasLimit(ctx sdk.Context, contractAddr sdk.AccAddress, ibcPort string, msg wasmvmtypes.CosmosMsg, gasLimit uint64) (events []sdk.Event, data [][]byte, err error) { +func (d MessageDispatcher) dispatchMsgWithGasLimit(ctx sdk.Context, contractAddr sdk.AccAddress, ibcPort string, msg wasmvmtypes.CosmosMsg, gasLimit uint64) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { limitedMeter := storetypes.NewGasMeter(gasLimit) subCtx := ctx.WithGasMeter(limitedMeter) @@ -70,13 +71,13 @@ func (d MessageDispatcher) dispatchMsgWithGasLimit(ctx sdk.Context, contractAddr err = errorsmod.Wrap(sdkerrors.ErrOutOfGas, "SubMsg hit gas limit") } }() - events, data, err = d.messenger.DispatchMsg(subCtx, contractAddr, ibcPort, msg) + events, data, msgResponses, err = d.messenger.DispatchMsg(subCtx, contractAddr, ibcPort, msg) // make sure we charge the parent what was spent spent := subCtx.GasMeter().GasConsumed() ctx.GasMeter().ConsumeGas(spent, "From limited Sub-Message") - return events, data, err + return events, data, msgResponses, err } // DispatchSubmessages builds a sandbox to execute these messages and returns the execution result to the contract @@ -101,10 +102,11 @@ func (d MessageDispatcher) DispatchSubmessages(ctx sdk.Context, contractAddr sdk var err error var events []sdk.Event var data [][]byte + var msgResponses [][]*codectypes.Any if limitGas { - events, data, err = d.dispatchMsgWithGasLimit(subCtx, contractAddr, ibcPort, msg.Msg, *msg.GasLimit) + events, data, msgResponses, err = d.dispatchMsgWithGasLimit(subCtx, contractAddr, ibcPort, msg.Msg, *msg.GasLimit) } else { - events, data, err = d.messenger.DispatchMsg(subCtx, contractAddr, ibcPort, msg.Msg) + events, data, msgResponses, err = d.messenger.DispatchMsg(subCtx, contractAddr, ibcPort, msg.Msg) } // if it succeeds, commit state changes from submessage, and pass on events to Event Manager @@ -142,10 +144,26 @@ func (d MessageDispatcher) DispatchSubmessages(ctx sdk.Context, contractAddr sdk if len(data) > 0 { responseData = data[0] } + + // For msgResponses we flatten the nested list into a flat list. In the majority of cases + // we only expect one message to be emitted and one response per message. But it might be possible + // to create multiple SDK messages from one CosmWasm message or we have multiple responses for one message. + // See https://github.com/CosmWasm/cosmwasm/issues/2009 for more information. + var msgResponsesFlattened []wasmvmtypes.MsgResponse + for _, singleMsgResponses := range msgResponses { + for _, singleMsgResponse := range singleMsgResponses { + msgResponsesFlattened = append(msgResponsesFlattened, wasmvmtypes.MsgResponse{ + TypeURL: singleMsgResponse.TypeUrl, + Value: singleMsgResponse.Value, + }) + } + } + result = wasmvmtypes.SubMsgResult{ Ok: &wasmvmtypes.SubMsgResponse{ - Events: sdkEventsToWasmVMEvents(filteredEvents), - Data: responseData, + Events: sdkEventsToWasmVMEvents(filteredEvents), + Data: responseData, + MsgResponses: msgResponsesFlattened, }, } } else { From d6ec8d4cf192acf303e7aba42edd54386b7a52a0 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Fri, 16 Feb 2024 17:41:15 +0100 Subject: [PATCH 25/45] Fix MockMessageHandler --- x/wasm/keeper/handler_plugin_test.go | 27 +++++---- x/wasm/keeper/msg_dispatcher.go | 5 ++ x/wasm/keeper/msg_dispatcher_test.go | 77 +++++++++++++------------- x/wasm/keeper/submsg_test.go | 4 +- x/wasm/keeper/wasmtesting/messenger.go | 13 +++-- 5 files changed, 69 insertions(+), 57 deletions(-) diff --git a/x/wasm/keeper/handler_plugin_test.go b/x/wasm/keeper/handler_plugin_test.go index 29639f4c25..68a86a2cc2 100644 --- a/x/wasm/keeper/handler_plugin_test.go +++ b/x/wasm/keeper/handler_plugin_test.go @@ -6,6 +6,7 @@ import ( wasmvm "github.com/CosmWasm/wasmvm/v2" wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" //nolint:staticcheck channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" @@ -29,13 +30,13 @@ func TestMessageHandlerChainDispatch(t *testing.T) { capturingHandler, gotMsgs := wasmtesting.NewCapturingMessageHandler() alwaysUnknownMsgHandler := &wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { - return nil, nil, types.ErrUnknownMsg + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { + return nil, nil, [][]*codectypes.Any{}, types.ErrUnknownMsg }, } assertNotCalledHandler := &wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { t.Fatal("not expected to be called") return }, @@ -58,8 +59,8 @@ func TestMessageHandlerChainDispatch(t *testing.T) { }, "stops iteration on handler error": { handlers: []Messenger{&wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { - return nil, nil, types.ErrInvalidMsg + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { + return nil, nil, [][]*codectypes.Any{}, types.ErrInvalidMsg }, }, assertNotCalledHandler}, expErr: types.ErrInvalidMsg, @@ -67,9 +68,9 @@ func TestMessageHandlerChainDispatch(t *testing.T) { "return events when handle": { handlers: []Messenger{ &wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { - _, data, _ = capturingHandler.DispatchMsg(ctx, contractAddr, contractIBCPortID, msg) - return []sdk.Event{sdk.NewEvent("myEvent", sdk.NewAttribute("foo", "bar"))}, data, nil + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { + _, data, msgResponses, _ = capturingHandler.DispatchMsg(ctx, contractAddr, contractIBCPortID, msg) + return []sdk.Event{sdk.NewEvent("myEvent", sdk.NewAttribute("foo", "bar"))}, data, msgResponses, nil }, }, }, @@ -86,7 +87,7 @@ func TestMessageHandlerChainDispatch(t *testing.T) { // when h := MessageHandlerChain{spec.handlers} - gotEvents, gotData, gotErr := h.DispatchMsg(sdk.Context{}, RandomAccountAddress(t), "anyPort", myMsg) + gotEvents, gotData, gotMsgResponses, gotErr := h.DispatchMsg(sdk.Context{}, RandomAccountAddress(t), "anyPort", myMsg) // then require.True(t, spec.expErr.Is(gotErr), "exp %v but got %#+v", spec.expErr, gotErr) @@ -95,6 +96,7 @@ func TestMessageHandlerChainDispatch(t *testing.T) { } assert.Equal(t, []wasmvmtypes.CosmosMsg{myMsg}, *gotMsgs) assert.Equal(t, [][]byte{{1}}, gotData) // {1} is default in capturing handler + assert.Equal(t, [][]*codectypes.Any{}, gotMsgResponses) assert.Equal(t, spec.expEvents, gotEvents) }) } @@ -208,7 +210,7 @@ func TestSDKMessageHandlerDispatch(t *testing.T) { // when ctx := sdk.Context{} h := NewSDKMessageHandler(MakeTestCodec(t), spec.srcRoute, MessageEncoders{Custom: spec.srcEncoder}) - gotEvents, gotData, gotErr := h.DispatchMsg(ctx, myContractAddr, "myPort", myContractMessage) + gotEvents, gotData, gotMsgResponses, gotErr := h.DispatchMsg(ctx, myContractAddr, "myPort", myContractMessage) // then require.True(t, spec.expErr.Is(gotErr), "exp %v but got %#+v", spec.expErr, gotErr) @@ -217,9 +219,11 @@ func TestSDKMessageHandlerDispatch(t *testing.T) { return } assert.Len(t, gotMsg, spec.expMsgDispatched) + assert.Len(t, gotMsgResponses, spec.expMsgDispatched) for i := 0; i < spec.expMsgDispatched; i++ { assert.Equal(t, myEvent, gotEvents[i]) assert.Equal(t, []byte(myData), gotData[i]) + assert.Equal(t, []*codectypes.Any(nil), gotMsgResponses[i]) } }) } @@ -308,7 +312,7 @@ func TestIBCRawPacketHandler(t *testing.T) { capturedPacket = nil // when h := NewIBCRawPacketHandler(capturePacketsSenderMock, spec.chanKeeper, spec.capKeeper) - evts, data, gotErr := h.DispatchMsg(ctx, RandomAccountAddress(t), ibcPort, wasmvmtypes.CosmosMsg{IBC: &wasmvmtypes.IBCMsg{SendPacket: &spec.srcMsg}}) //nolint:gosec + evts, data, msgResponses, gotErr := h.DispatchMsg(ctx, RandomAccountAddress(t), ibcPort, wasmvmtypes.CosmosMsg{IBC: &wasmvmtypes.IBCMsg{SendPacket: &spec.srcMsg}}) //nolint:gosec // then require.True(t, spec.expErr.Is(gotErr), "exp %v but got %#+v", spec.expErr, gotErr) if spec.expErr != nil { @@ -317,6 +321,7 @@ func TestIBCRawPacketHandler(t *testing.T) { assert.Nil(t, evts) require.NotNil(t, data) + require.Len(t, msgResponses, 0) expMsg := types.MsgIBCSendResponse{Sequence: 1} diff --git a/x/wasm/keeper/msg_dispatcher.go b/x/wasm/keeper/msg_dispatcher.go index 4344f9f898..794e0ced06 100644 --- a/x/wasm/keeper/msg_dispatcher.go +++ b/x/wasm/keeper/msg_dispatcher.go @@ -15,9 +15,14 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/CosmWasm/wasmd/x/wasm/keeper/wasmtesting" "github.com/CosmWasm/wasmd/x/wasm/types" ) +var _ Messenger = &wasmtesting.MockMessageHandler{} +var _ Messenger = MessageHandlerChain{} +var _ Messenger = SDKMessageHandler{} + // Messenger is an extension point for custom wasmd message handling type Messenger interface { // DispatchMsg encodes the wasmVM message and dispatches it. diff --git a/x/wasm/keeper/msg_dispatcher_test.go b/x/wasm/keeper/msg_dispatcher_test.go index d9b0a9d6e8..c7efef83f2 100644 --- a/x/wasm/keeper/msg_dispatcher_test.go +++ b/x/wasm/keeper/msg_dispatcher_test.go @@ -13,6 +13,7 @@ import ( "cosmossdk.io/log" storetypes "cosmossdk.io/store/types" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/CosmWasm/wasmd/x/wasm/keeper/wasmtesting" @@ -34,8 +35,8 @@ func TestDispatchSubmessages(t *testing.T) { msgs: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyError}}, replyer: noReplyCalled, msgHandler: &wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { - return nil, [][]byte{[]byte("myData")}, nil + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { + return nil, [][]byte{[]byte("myData")}, [][]*codectypes.Any{}, nil }, }, expCommits: []bool{true}, @@ -44,8 +45,8 @@ func TestDispatchSubmessages(t *testing.T) { msgs: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplySuccess}}, replyer: noReplyCalled, msgHandler: &wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { - return nil, nil, errors.New("test, ignore") + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { + return nil, nil, [][]*codectypes.Any{}, errors.New("test, ignore") }, }, expCommits: []bool{false}, @@ -61,8 +62,8 @@ func TestDispatchSubmessages(t *testing.T) { }, }, msgHandler: &wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { - return nil, [][]byte{[]byte("myData")}, nil + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { + return nil, [][]byte{[]byte("myData")}, [][]*codectypes.Any{}, nil }, }, expData: []byte("myReplyData"), @@ -78,8 +79,8 @@ func TestDispatchSubmessages(t *testing.T) { }, }, msgHandler: &wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { - return nil, nil, errors.New("my error") + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { + return nil, nil, [][]*codectypes.Any{}, errors.New("my error") }, }, expData: []byte("myReplyData"), @@ -96,9 +97,9 @@ func TestDispatchSubmessages(t *testing.T) { }, }, msgHandler: &wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { myEvents := []sdk.Event{{Type: "myEvent", Attributes: []abci.EventAttribute{{Key: "foo", Value: "bar"}}}} - return myEvents, [][]byte{[]byte("myData")}, nil + return myEvents, [][]byte{[]byte("myData")}, [][]*codectypes.Any{}, nil }, }, expData: []byte("myReplyData"), @@ -117,10 +118,10 @@ func TestDispatchSubmessages(t *testing.T) { }}, replyer: &mockReplyer{}, msgHandler: &wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { myEvents := []sdk.Event{{Type: "myEvent", Attributes: []abci.EventAttribute{{Key: "foo", Value: "bar"}}}} ctx.EventManager().EmitEvents(myEvents) - return nil, nil, nil + return nil, nil, [][]*codectypes.Any{}, nil }, }, expCommits: []bool{true}, @@ -135,10 +136,10 @@ func TestDispatchSubmessages(t *testing.T) { }}, replyer: &mockReplyer{}, msgHandler: &wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { myEvents := []sdk.Event{{Type: "myEvent", Attributes: []abci.EventAttribute{{Key: "foo", Value: "bar"}}}} ctx.EventManager().EmitEvents(myEvents) - return nil, nil, errors.New("testing") + return nil, nil, [][]*codectypes.Any{}, errors.New("testing") }, }, expCommits: []bool{false}, @@ -154,8 +155,8 @@ func TestDispatchSubmessages(t *testing.T) { }, }, msgHandler: &wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { - return nil, nil, nil + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { + return nil, nil, [][]*codectypes.Any{}, nil }, }, expCommits: []bool{false}, @@ -172,9 +173,9 @@ func TestDispatchSubmessages(t *testing.T) { }, }, msgHandler: &wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { ctx.GasMeter().ConsumeGas(storetypes.Gas(101), "testing") - return nil, [][]byte{[]byte("someData")}, nil + return nil, [][]byte{[]byte("someData")}, [][]*codectypes.Any{}, nil }, }, expData: []byte("myReplyData"), @@ -187,9 +188,9 @@ func TestDispatchSubmessages(t *testing.T) { }}, replyer: &mockReplyer{}, msgHandler: &wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { ctx.GasMeter().ConsumeGas(storetypes.Gas(1), "testing") - return nil, [][]byte{[]byte("someData")}, nil + return nil, [][]byte{[]byte("someData")}, [][]*codectypes.Any{}, nil }, }, expCommits: []bool{true}, @@ -198,8 +199,8 @@ func TestDispatchSubmessages(t *testing.T) { msgs: []wasmvmtypes.SubMsg{{ID: 1, ReplyOn: wasmvmtypes.ReplyNever}, {ID: 2, ReplyOn: wasmvmtypes.ReplyNever}}, replyer: &mockReplyer{}, msgHandler: &wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { - return nil, [][]byte{nil}, nil + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { + return nil, [][]byte{nil}, [][]*codectypes.Any{}, nil }, }, expCommits: []bool{true, true}, @@ -208,8 +209,8 @@ func TestDispatchSubmessages(t *testing.T) { msgs: []wasmvmtypes.SubMsg{{ID: 1, ReplyOn: wasmvmtypes.ReplyNever}, {ID: 2, ReplyOn: wasmvmtypes.ReplyNever}}, replyer: &mockReplyer{}, msgHandler: &wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { - return nil, [][]byte{{}}, nil + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { + return nil, [][]byte{{}}, [][]*codectypes.Any{}, nil }, }, expCommits: []bool{true, true}, @@ -218,8 +219,8 @@ func TestDispatchSubmessages(t *testing.T) { msgs: []wasmvmtypes.SubMsg{{ID: 1, ReplyOn: wasmvmtypes.ReplyNever}, {ID: 2, ReplyOn: wasmvmtypes.ReplyNever}}, replyer: &mockReplyer{}, msgHandler: &wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { - return nil, [][]byte{{}}, errors.New("testing") + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { + return nil, [][]byte{{}}, [][]*codectypes.Any{}, errors.New("testing") }, }, expCommits: []bool{false, false}, @@ -233,8 +234,8 @@ func TestDispatchSubmessages(t *testing.T) { }, }, msgHandler: &wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { - return nil, nil, errors.New("my error") + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { + return nil, nil, [][]*codectypes.Any{}, errors.New("my error") }, }, expData: []byte("myReplyData:2"), @@ -251,8 +252,8 @@ func TestDispatchSubmessages(t *testing.T) { }, }, msgHandler: &wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { - return nil, nil, errors.New("my error") + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { + return nil, nil, [][]*codectypes.Any{}, errors.New("my error") }, }, expData: []byte("myReplyData:1"), @@ -269,8 +270,8 @@ func TestDispatchSubmessages(t *testing.T) { }, }, msgHandler: &wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { - return nil, nil, errors.New("my error") + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { + return nil, nil, [][]*codectypes.Any{}, errors.New("my error") }, }, expData: []byte{}, @@ -286,12 +287,12 @@ func TestDispatchSubmessages(t *testing.T) { }, }, msgHandler: &wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { myEvents := []sdk.Event{ sdk.NewEvent("message"), sdk.NewEvent("execute", sdk.NewAttribute("foo", "bar")), } - return myEvents, [][]byte{[]byte("myData")}, nil + return myEvents, [][]byte{[]byte("myData")}, [][]*codectypes.Any{}, nil }, }, expData: nil, @@ -328,14 +329,14 @@ func TestDispatchSubmessages(t *testing.T) { }, }, msgHandler: &wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { events = []sdk.Event{ sdk.NewEvent("message", sdk.NewAttribute("_contract_address", contractAddr.String())), // we don't know what the contarctAddr will be so we can't use it in the final tests sdk.NewEvent("execute", sdk.NewAttribute("_contract_address", "placeholder-random-addr")), sdk.NewEvent("wasm", sdk.NewAttribute("random", "data")), } - return events, [][]byte{[]byte("subData")}, nil + return events, [][]byte{[]byte("subData")}, [][]*codectypes.Any{}, nil }, }, expData: []byte("subData"), @@ -370,14 +371,14 @@ func TestDispatchSubmessages(t *testing.T) { }, }, msgHandler: &wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { events = []sdk.Event{ // this is filtered out sdk.NewEvent("message", sdk.NewAttribute("stargate", "something-something")), // we still emit this to the client, but not the contract sdk.NewEvent("non-determinstic"), } - return events, [][]byte{[]byte("subData")}, nil + return events, [][]byte{[]byte("subData")}, [][]*codectypes.Any{}, nil }, }, expData: []byte("subData"), diff --git a/x/wasm/keeper/submsg_test.go b/x/wasm/keeper/submsg_test.go index 016e4a92ae..971f0d9648 100644 --- a/x/wasm/keeper/submsg_test.go +++ b/x/wasm/keeper/submsg_test.go @@ -243,7 +243,7 @@ func TestDispatchSubMsgErrorHandling(t *testing.T) { "send tokens": { submsgID: 5, msg: validBankSend, - resultAssertions: []assertion{assertReturnedEvents(0), assertGasUsed(107_000, 110_000)}, + resultAssertions: []assertion{assertReturnedEvents(0), assertGasUsed(110_000, 111_000)}, }, "not enough tokens": { submsgID: 6, @@ -263,7 +263,7 @@ func TestDispatchSubMsgErrorHandling(t *testing.T) { msg: validBankSend, gasLimit: &subGasLimit, // uses same gas as call without limit (note we do not charge the 40k on reply) - resultAssertions: []assertion{assertReturnedEvents(0), assertGasUsed(107_000, 110_000)}, + resultAssertions: []assertion{assertReturnedEvents(0), assertGasUsed(110_000, 112_000)}, }, "not enough tokens with limit": { submsgID: 16, diff --git a/x/wasm/keeper/wasmtesting/messenger.go b/x/wasm/keeper/wasmtesting/messenger.go index 3290580953..664718ea66 100644 --- a/x/wasm/keeper/wasmtesting/messenger.go +++ b/x/wasm/keeper/wasmtesting/messenger.go @@ -4,15 +4,16 @@ import ( "errors" wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" ) type MockMessageHandler struct { - DispatchMsgFn func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) + DispatchMsgFn func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) } -func (m *MockMessageHandler) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { +func (m *MockMessageHandler) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { if m.DispatchMsgFn == nil { panic("not expected to be called") } @@ -22,18 +23,18 @@ func (m *MockMessageHandler) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAd func NewCapturingMessageHandler() (*MockMessageHandler, *[]wasmvmtypes.CosmosMsg) { var messages []wasmvmtypes.CosmosMsg return &MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { messages = append(messages, msg) // return one data item so that this doesn't cause an error in submessage processing (it takes the first element from data) - return nil, [][]byte{{1}}, nil + return nil, [][]byte{{1}}, [][]*codectypes.Any{}, nil }, }, &messages } func NewErroringMessageHandler() *MockMessageHandler { return &MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { - return nil, nil, errors.New("test, ignore") + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { + return nil, nil, [][]*codectypes.Any{}, errors.New("test, ignore") }, } } From 219da83e5ae6821a7adfd83ba3cba403aaab209f Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Mon, 19 Feb 2024 16:21:05 +0100 Subject: [PATCH 26/45] Run gofumpt --- x/wasm/keeper/msg_dispatcher.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/x/wasm/keeper/msg_dispatcher.go b/x/wasm/keeper/msg_dispatcher.go index 794e0ced06..e567fd09d7 100644 --- a/x/wasm/keeper/msg_dispatcher.go +++ b/x/wasm/keeper/msg_dispatcher.go @@ -19,9 +19,11 @@ import ( "github.com/CosmWasm/wasmd/x/wasm/types" ) -var _ Messenger = &wasmtesting.MockMessageHandler{} -var _ Messenger = MessageHandlerChain{} -var _ Messenger = SDKMessageHandler{} +var ( + _ Messenger = &wasmtesting.MockMessageHandler{} + _ Messenger = MessageHandlerChain{} + _ Messenger = SDKMessageHandler{} +) // Messenger is an extension point for custom wasmd message handling type Messenger interface { From 7f88c95aba19d9e6fc86aa7d4c7e43041f37770a Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Mon, 19 Feb 2024 16:54:48 +0100 Subject: [PATCH 27/45] Format imports --- x/wasm/keeper/handler_plugin_test.go | 2 +- x/wasm/keeper/wasmtesting/messenger.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x/wasm/keeper/handler_plugin_test.go b/x/wasm/keeper/handler_plugin_test.go index 68a86a2cc2..ba20f4a9b1 100644 --- a/x/wasm/keeper/handler_plugin_test.go +++ b/x/wasm/keeper/handler_plugin_test.go @@ -6,7 +6,6 @@ import ( wasmvm "github.com/CosmWasm/wasmvm/v2" wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" - codectypes "github.com/cosmos/cosmos-sdk/codec/types" capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" //nolint:staticcheck channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" @@ -18,6 +17,7 @@ import ( sdkmath "cosmossdk.io/math" "github.com/cosmos/cosmos-sdk/baseapp" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" diff --git a/x/wasm/keeper/wasmtesting/messenger.go b/x/wasm/keeper/wasmtesting/messenger.go index 664718ea66..6c133406a5 100644 --- a/x/wasm/keeper/wasmtesting/messenger.go +++ b/x/wasm/keeper/wasmtesting/messenger.go @@ -4,8 +4,8 @@ import ( "errors" wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" - codectypes "github.com/cosmos/cosmos-sdk/codec/types" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" ) From 0ca56bd466a80b70415fd27e7b453a4033cb157f Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Mon, 19 Feb 2024 18:02:42 +0100 Subject: [PATCH 28/45] Pass Payload from submsg to reply --- x/wasm/keeper/msg_dispatcher.go | 5 +++-- x/wasm/keeper/msg_dispatcher_test.go | 26 ++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/x/wasm/keeper/msg_dispatcher.go b/x/wasm/keeper/msg_dispatcher.go index e567fd09d7..814c6110b3 100644 --- a/x/wasm/keeper/msg_dispatcher.go +++ b/x/wasm/keeper/msg_dispatcher.go @@ -183,8 +183,9 @@ func (d MessageDispatcher) DispatchSubmessages(ctx sdk.Context, contractAddr sdk // now handle the reply, we use the parent context, and abort on error reply := wasmvmtypes.Reply{ - ID: msg.ID, - Result: result, + ID: msg.ID, + Result: result, + Payload: msg.Payload, } // we can ignore any result returned as there is nothing to do with the data diff --git a/x/wasm/keeper/msg_dispatcher_test.go b/x/wasm/keeper/msg_dispatcher_test.go index c7efef83f2..a17a73281d 100644 --- a/x/wasm/keeper/msg_dispatcher_test.go +++ b/x/wasm/keeper/msg_dispatcher_test.go @@ -3,6 +3,7 @@ package keeper import ( "errors" "fmt" + "reflect" "testing" wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" @@ -347,6 +348,31 @@ func TestDispatchSubmessages(t *testing.T) { sdk.NewEvent("wasm-reply"), }, }, + "wasm reply gets payload": { + // put fake wasmmsg in here to show where it comes from + msgs: []wasmvmtypes.SubMsg{{ID: 1, ReplyOn: wasmvmtypes.ReplyAlways, Payload: []byte("payloadData"), Msg: wasmvmtypes.CosmosMsg{Wasm: &wasmvmtypes.WasmMsg{}}}}, + replyer: &mockReplyer{ + replyFn: func(ctx sdk.Context, contractAddress sdk.AccAddress, reply wasmvmtypes.Reply) ([]byte, error) { + if reply.Result.Err != "" { + return nil, errors.New(reply.Result.Err) + } + + // ensure we got the payload + if !reflect.DeepEqual(reply.Payload, []byte("payloadData")) { + return nil, fmt.Errorf("payload mismatch: %s != 'payloadData'", reply.Payload) + } + + // update data from what we got in + return reply.Result.Ok.Data, nil + }, + }, + msgHandler: &wasmtesting.MockMessageHandler{ + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { + return nil, nil, [][]*codectypes.Any{}, nil + }, + }, + expCommits: []bool{true}, + }, "non-wasm reply events get filtered": { // show events from a stargate message gets filtered out msgs: []wasmvmtypes.SubMsg{{ID: 1, ReplyOn: wasmvmtypes.ReplyAlways, Msg: wasmvmtypes.CosmosMsg{Any: &wasmvmtypes.AnyMsg{}}}}, From 97694f1c22b10878f6f9063427482c43a93c477b Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Tue, 20 Feb 2024 11:14:45 +0100 Subject: [PATCH 29/45] Add extra error for wasmvm errors --- x/wasm/keeper/keeper.go | 16 ++++++++-------- x/wasm/keeper/keeper_test.go | 6 +++--- x/wasm/keeper/recurse_test.go | 2 +- x/wasm/keeper/reflect_test.go | 2 +- x/wasm/types/errors.go | 3 +++ 5 files changed, 16 insertions(+), 13 deletions(-) diff --git a/x/wasm/keeper/keeper.go b/x/wasm/keeper/keeper.go index 3b833b0051..393a9bbad3 100644 --- a/x/wasm/keeper/keeper.go +++ b/x/wasm/keeper/keeper.go @@ -321,7 +321,7 @@ func (k Keeper) instantiate( res, gasUsed, err := k.wasmVM.Instantiate(codeInfo.CodeHash, env, info, initMsg, vmStore, cosmwasmAPI, querier, k.gasMeter(sdkCtx), gas, costJSONDeserialization) k.consumeRuntimeGas(sdkCtx, gasUsed) if err != nil { - return nil, nil, errorsmod.Wrap(types.ErrInstantiateFailed, err.Error()) + return nil, nil, errorsmod.Wrap(types.ErrVMError, err.Error()) } if res.Err != "" { return nil, nil, errorsmod.Wrap(types.ErrInstantiateFailed, res.Err) @@ -334,7 +334,7 @@ func (k Keeper) instantiate( // check for IBC flag report, err := k.wasmVM.AnalyzeCode(codeInfo.CodeHash) if err != nil { - return nil, nil, errorsmod.Wrap(types.ErrInstantiateFailed, err.Error()) + return nil, nil, errorsmod.Wrap(types.ErrVMError, err.Error()) } if report.HasIBCEntryPoints { // register IBC port @@ -405,7 +405,7 @@ func (k Keeper) execute(ctx context.Context, contractAddress, caller sdk.AccAddr res, gasUsed, execErr := k.wasmVM.Execute(codeInfo.CodeHash, env, info, msg, prefixStore, cosmwasmAPI, querier, k.gasMeter(sdkCtx), gas, costJSONDeserialization) k.consumeRuntimeGas(sdkCtx, gasUsed) if execErr != nil { - return nil, errorsmod.Wrap(types.ErrExecuteFailed, execErr.Error()) + return nil, errorsmod.Wrap(types.ErrVMError, execErr.Error()) } if res.Err != "" { return nil, errorsmod.Wrap(types.ErrExecuteFailed, res.Err) @@ -458,7 +458,7 @@ func (k Keeper) migrate( // check for IBC flag switch report, err := k.wasmVM.AnalyzeCode(newCodeInfo.CodeHash); { case err != nil: - return nil, errorsmod.Wrap(types.ErrMigrationFailed, err.Error()) + return nil, errorsmod.Wrap(types.ErrVMError, err.Error()) case !report.HasIBCEntryPoints && contractInfo.IBCPortID != "": // prevent update to non ibc contract return nil, errorsmod.Wrap(types.ErrMigrationFailed, "requires ibc callbacks") @@ -482,7 +482,7 @@ func (k Keeper) migrate( res, gasUsed, err := k.wasmVM.Migrate(newCodeInfo.CodeHash, env, msg, vmStore, cosmwasmAPI, &querier, k.gasMeter(sdkCtx), gas, costJSONDeserialization) k.consumeRuntimeGas(sdkCtx, gasUsed) if err != nil { - return nil, errorsmod.Wrap(types.ErrMigrationFailed, err.Error()) + return nil, errorsmod.Wrap(types.ErrVMError, err.Error()) } if res.Err != "" { return nil, errorsmod.Wrap(types.ErrMigrationFailed, res.Err) @@ -547,7 +547,7 @@ func (k Keeper) Sudo(ctx context.Context, contractAddress sdk.AccAddress, msg [] res, gasUsed, execErr := k.wasmVM.Sudo(codeInfo.CodeHash, env, msg, prefixStore, cosmwasmAPI, querier, k.gasMeter(sdkCtx), gas, costJSONDeserialization) k.consumeRuntimeGas(sdkCtx, gasUsed) if execErr != nil { - return nil, errorsmod.Wrap(types.ErrExecuteFailed, execErr.Error()) + return nil, errorsmod.Wrap(types.ErrVMError, execErr.Error()) } if res.Err != "" { return nil, errorsmod.Wrap(types.ErrExecuteFailed, res.Err) @@ -587,7 +587,7 @@ func (k Keeper) reply(ctx sdk.Context, contractAddress sdk.AccAddress, reply was res, gasUsed, execErr := k.wasmVM.Reply(codeInfo.CodeHash, env, reply, prefixStore, cosmwasmAPI, querier, k.gasMeter(ctx), gas, costJSONDeserialization) k.consumeRuntimeGas(ctx, gasUsed) if execErr != nil { - return nil, errorsmod.Wrap(types.ErrExecuteFailed, execErr.Error()) + return nil, errorsmod.Wrap(types.ErrVMError, execErr.Error()) } if res.Err != "" { return nil, errorsmod.Wrap(types.ErrExecuteFailed, res.Err) @@ -773,7 +773,7 @@ func (k Keeper) QuerySmart(ctx context.Context, contractAddr sdk.AccAddress, req queryResult, gasUsed, qErr := k.wasmVM.Query(codeInfo.CodeHash, env, req, prefixStore, cosmwasmAPI, querier, k.gasMeter(sdkCtx), k.runtimeGasForContract(sdkCtx), costJSONDeserialization) k.consumeRuntimeGas(sdkCtx, gasUsed) if qErr != nil { - return nil, errorsmod.Wrap(types.ErrQueryFailed, qErr.Error()) + return nil, errorsmod.Wrap(types.ErrVMError, qErr.Error()) } if queryResult.Err != "" { return nil, errorsmod.Wrap(types.ErrQueryFailed, queryResult.Err) diff --git a/x/wasm/keeper/keeper_test.go b/x/wasm/keeper/keeper_test.go index d39554ff48..cec91d56c5 100644 --- a/x/wasm/keeper/keeper_test.go +++ b/x/wasm/keeper/keeper_test.go @@ -1023,9 +1023,9 @@ func TestExecuteWithPanic(t *testing.T) { // let's make sure we get a reasonable error, no panic/crash _, err = keepers.ContractKeeper.Execute(ctx, addr, fred, []byte(`{"panic":{}}`), topUp) require.Error(t, err) - require.True(t, errors.Is(err, types.ErrExecuteFailed)) + require.True(t, errors.Is(err, types.ErrVMError)) // test with contains as "Display" implementation of the Wasmer "RuntimeError" is different for Mac and Linux - assert.Contains(t, err.Error(), "Error calling the VM: Error executing Wasm: Wasmer runtime error: RuntimeError: Aborted: panicked at 'This page intentionally faulted', src/contract.rs:169:5: execute wasm contract failed") + assert.Contains(t, err.Error(), "Error calling the VM: Error executing Wasm: Wasmer runtime error: RuntimeError: Aborted: panicked at 'This page intentionally faulted', src/contract.rs:169:5: wasmvm error") } func TestExecuteWithCpuLoop(t *testing.T) { @@ -1251,7 +1251,7 @@ func TestMigrate(t *testing.T) { initMsg: initMsgBz, fromCodeID: originalCodeID, toCodeID: originalCodeID, - expErr: types.ErrMigrationFailed, + expErr: types.ErrVMError, }, "fail when no IBC callbacks": { admin: fred, diff --git a/x/wasm/keeper/recurse_test.go b/x/wasm/keeper/recurse_test.go index a0a2bae54a..c5676be659 100644 --- a/x/wasm/keeper/recurse_test.go +++ b/x/wasm/keeper/recurse_test.go @@ -264,7 +264,7 @@ func TestLimitRecursiveQueryGas(t *testing.T) { expectQueriesFromContract: 10, expectOutOfGas: false, expectError: "query wasm contract failed", // Error we get from the contract instance doing the failing query, not wasmd - expectedGas: 10*(GasWork2k+GasReturnHashed) - 249, + expectedGas: 10*(GasWork2k+GasReturnHashed) + 3124, }, } diff --git a/x/wasm/keeper/reflect_test.go b/x/wasm/keeper/reflect_test.go index edb338b918..d6a14ae361 100644 --- a/x/wasm/keeper/reflect_test.go +++ b/x/wasm/keeper/reflect_test.go @@ -222,7 +222,7 @@ func TestRustPanicIsHandled(t *testing.T) { // when panic is triggered msg := []byte(`{"panic":{}}`) gotData, err := keeper.Execute(ctx, contractAddr, creator, msg, nil) - require.ErrorIs(t, err, types.ErrExecuteFailed) + require.ErrorIs(t, err, types.ErrVMError) assert.Contains(t, err.Error(), "panicked at 'This page intentionally faulted'") assert.Nil(t, gotData) } diff --git a/x/wasm/types/errors.go b/x/wasm/types/errors.go index 027f001ac1..035d50d389 100644 --- a/x/wasm/types/errors.go +++ b/x/wasm/types/errors.go @@ -86,6 +86,9 @@ var ( ErrNoSuchCodeFn = WasmVMFlavouredErrorFactory(errorsmod.Register(DefaultCodespace, 28, "no such code"), func(id uint64) error { return wasmvmtypes.NoSuchCode{CodeID: id} }, ) + + // ErrVMError means an error occurred in wasmvm (not in the contract itself, but in the host environment) + ErrVMError = errorsmod.Register(DefaultCodespace, 29, "wasmvm error") ) // WasmVMErrorable mapped error type in wasmvm and are not redacted From d94360cb907ff2446f6fe341bfd4bbc507e6f426 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Wed, 21 Feb 2024 10:44:07 +0100 Subject: [PATCH 30/45] Do not redact contract errors --- x/wasm/keeper/keeper_test.go | 26 ++++++++++++++++++++++++++ x/wasm/keeper/msg_dispatcher.go | 6 ++++++ x/wasm/types/errors.go | 20 ++++++++++++++++---- 3 files changed, 48 insertions(+), 4 deletions(-) diff --git a/x/wasm/keeper/keeper_test.go b/x/wasm/keeper/keeper_test.go index cec91d56c5..e6811c55f7 100644 --- a/x/wasm/keeper/keeper_test.go +++ b/x/wasm/keeper/keeper_test.go @@ -712,6 +712,32 @@ func TestInstantiateWithNonExistingCodeID(t *testing.T) { require.Nil(t, addr) } +func TestContractErrorRedacting(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) + creator := sdk.AccAddress(bytes.Repeat([]byte{1}, address.Len)) + keepers.Faucet.Fund(ctx, creator, deposit...) + example := StoreHackatomExampleContract(t, ctx, keepers) + + initMsg := HackatomExampleInitMsg{ + Verifier: []byte{1, 2, 3}, // invalid length + Beneficiary: RandomAccountAddress(t), + } + initMsgBz, err := json.Marshal(initMsg) + require.NoError(t, err) + + em := sdk.NewEventManager() + + _, _, err = keepers.ContractKeeper.Instantiate(ctx.WithEventManager(em), example.CodeID, creator, nil, initMsgBz, "demo contract 1", nil) + require.Error(t, err) + require.Contains(t, err.Error(), "addr_validate errored: invalid address") + + err = redactError(err) + // contract error should not be redacted + require.Contains(t, err.Error(), "addr_validate errored: invalid address") +} + func TestInstantiateWithContractDataResponse(t *testing.T) { ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) diff --git a/x/wasm/keeper/msg_dispatcher.go b/x/wasm/keeper/msg_dispatcher.go index 814c6110b3..c670a23225 100644 --- a/x/wasm/keeper/msg_dispatcher.go +++ b/x/wasm/keeper/msg_dispatcher.go @@ -215,6 +215,12 @@ func redactError(err error) error { // sdk/5 is insufficient funds (on bank send) // (we can theoretically redact less in the future, but this is a first step to safety) codespace, code, _ := errorsmod.ABCIInfo(err, false) + + // Also do not redact any errors that are coming from the contract, + // as they are always deterministic + if codespace == types.DefaultCodespace && contains(types.ContractErrorCodes, code) { + return err + } return fmt.Errorf("codespace: %s, code: %d", codespace, code) } diff --git a/x/wasm/types/errors.go b/x/wasm/types/errors.go index 035d50d389..724c0c38fa 100644 --- a/x/wasm/types/errors.go +++ b/x/wasm/types/errors.go @@ -10,6 +10,10 @@ import ( var ( DefaultCodespace = ModuleName + // ContractErrorCodes are the error codes for errors returned by the contract + // Since contract execution is deterministic, the errors are also deterministic + ContractErrorCodes = []uint32{InstantiateErrorCode, ExecuteErrorCode, QueryErrorCode, MigrateErrorCode} + // Note: never use code 1 for any errors - that is reserved for ErrInternal in the core cosmos sdk // ErrCreateFailed error for wasm code that has already been uploaded or failed @@ -19,10 +23,10 @@ var ( ErrAccountExists = errorsmod.Register(DefaultCodespace, 3, "contract account already exists") // ErrInstantiateFailed error for rust instantiate contract failure - ErrInstantiateFailed = errorsmod.Register(DefaultCodespace, 4, "instantiate wasm contract failed") + ErrInstantiateFailed = errorsmod.Register(DefaultCodespace, InstantiateErrorCode, "instantiate wasm contract failed") // ErrExecuteFailed error for rust execution contract failure - ErrExecuteFailed = errorsmod.Register(DefaultCodespace, 5, "execute wasm contract failed") + ErrExecuteFailed = errorsmod.Register(DefaultCodespace, ExecuteErrorCode, "execute wasm contract failed") // ErrGasLimit error for out of gas ErrGasLimit = errorsmod.Register(DefaultCodespace, 6, "insufficient gas") @@ -34,13 +38,13 @@ var ( ErrNotFound = errorsmod.Register(DefaultCodespace, 8, "not found") // ErrQueryFailed error for rust smart query contract failure - ErrQueryFailed = errorsmod.Register(DefaultCodespace, 9, "query wasm contract failed") + ErrQueryFailed = errorsmod.Register(DefaultCodespace, QueryErrorCode, "query wasm contract failed") // ErrInvalidMsg error when we cannot process the error returned from the contract ErrInvalidMsg = errorsmod.Register(DefaultCodespace, 10, "invalid CosmosMsg from the contract") // ErrMigrationFailed error for rust execution contract failure - ErrMigrationFailed = errorsmod.Register(DefaultCodespace, 11, "migrate wasm contract failed") + ErrMigrationFailed = errorsmod.Register(DefaultCodespace, MigrateErrorCode, "migrate wasm contract failed") // ErrEmpty error for empty content ErrEmpty = errorsmod.Register(DefaultCodespace, 12, "empty") @@ -91,6 +95,14 @@ var ( ErrVMError = errorsmod.Register(DefaultCodespace, 29, "wasmvm error") ) +// Error codes for wasm contract errors +const ( + InstantiateErrorCode = 4 + ExecuteErrorCode = 5 + QueryErrorCode = 9 + MigrateErrorCode = 11 +) + // WasmVMErrorable mapped error type in wasmvm and are not redacted type WasmVMErrorable interface { // ToWasmVMError convert instance to wasmvm friendly error if possible otherwise root cause. never nil From 9cc1a5afe495a1a1ce95d30cccbb9dd48bf96923 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Wed, 21 Feb 2024 14:19:56 +0100 Subject: [PATCH 31/45] Implement grpc query --- .../keeper/query_plugin_integration_test.go | 53 +++++++++++++++ x/wasm/keeper/query_plugins.go | 65 +++++++++++++++++-- x/wasm/keeper/query_plugins_test.go | 2 +- 3 files changed, 115 insertions(+), 5 deletions(-) diff --git a/x/wasm/keeper/query_plugin_integration_test.go b/x/wasm/keeper/query_plugin_integration_test.go index 4ff5954c82..f9d126e20e 100644 --- a/x/wasm/keeper/query_plugin_integration_test.go +++ b/x/wasm/keeper/query_plugin_integration_test.go @@ -3,6 +3,7 @@ package keeper import ( "bytes" "encoding/json" + "errors" "fmt" "strings" "testing" @@ -116,6 +117,58 @@ func TestReflectStargateQuery(t *testing.T) { assert.Equal(t, simpleBalance.Amount[0].Denom, expectedBalance[0].Denom) } +func TestReflectGrpcQuery(t *testing.T) { + queryPlugins := (*reflectPlugins()).Merge(&QueryPlugins{ + Grpc: func(ctx sdk.Context, request *wasmvmtypes.GrpcQuery) (proto.Message, error) { + if request.Path == "cosmos.bank.v1beta1.Query/AllBalances" { + return &banktypes.QueryAllBalancesResponse{ + Balances: sdk.NewCoins(), + }, nil + } + return nil, errors.New("unsupported request") + }, + }) + cdc := MakeEncodingConfig(t).Codec + ctx, keepers := CreateTestInput(t, false, ReflectCapabilities, WithMessageEncoders(reflectEncoders(cdc)), WithQueryPlugins(&queryPlugins)) + keeper := keepers.WasmKeeper + + creator := RandomAccountAddress(t) + + // upload code + codeID, _, err := keepers.ContractKeeper.Create(ctx, creator, testdata.ReflectContractWasm(), nil) + require.NoError(t, err) + require.Equal(t, uint64(1), codeID) + + // creator instantiates a contract + contractAddr, _, err := keepers.ContractKeeper.Instantiate(ctx, codeID, creator, nil, []byte("{}"), "reflect contract 1", sdk.NewCoins()) + require.NoError(t, err) + require.NotEmpty(t, contractAddr) + + // now grpc query for the bank balance + cosmosBankQuery := banktypes.NewQueryAllBalancesRequest(creator, nil, false) + cosmosBankQueryBz, err := proto.Marshal(cosmosBankQuery) + require.NoError(t, err) + reflectQuery := wasmvmtypes.QueryRequest{ + Grpc: &wasmvmtypes.GrpcQuery{ + Path: "cosmos.bank.v1beta1.Query/AllBalances", + Data: cosmosBankQueryBz, + }, + } + reflectQueryBz, err := json.Marshal(testdata.ReflectQueryMsg{ + Chain: &testdata.ChainQuery{Request: &reflectQuery}, + }) + require.NoError(t, err) + // query the reflect contract + reflectRespBz, err := keeper.QuerySmart(ctx, contractAddr, reflectQueryBz) + require.NoError(t, err) + var reflectResp testdata.ChainResponse + mustUnmarshal(t, reflectRespBz, &reflectResp) + // now unmarshal the protobuf response + var grpcBalance banktypes.QueryAllBalancesResponse + err = proto.Unmarshal(reflectResp.Data, &grpcBalance) + require.NoError(t, err) +} + func TestReflectTotalSupplyQuery(t *testing.T) { cdc := MakeEncodingConfig(t).Codec ctx, keepers := CreateTestInput(t, false, ReflectCapabilities, WithMessageEncoders(reflectEncoders(cdc)), WithQueryPlugins(reflectPlugins())) diff --git a/x/wasm/keeper/query_plugins.go b/x/wasm/keeper/query_plugins.go index 488e4d3adb..ee62da2f51 100644 --- a/x/wasm/keeper/query_plugins.go +++ b/x/wasm/keeper/query_plugins.go @@ -90,6 +90,7 @@ type QueryPlugins struct { IBC func(ctx sdk.Context, caller sdk.AccAddress, request *wasmvmtypes.IBCQuery) ([]byte, error) Staking func(ctx sdk.Context, request *wasmvmtypes.StakingQuery) ([]byte, error) Stargate func(ctx sdk.Context, request *wasmvmtypes.StargateQuery) ([]byte, error) + Grpc func(ctx sdk.Context, request *wasmvmtypes.GrpcQuery) (proto.Message, error) Wasm func(ctx sdk.Context, request *wasmvmtypes.WasmQuery) ([]byte, error) Distribution func(ctx sdk.Context, request *wasmvmtypes.DistributionQuery) ([]byte, error) } @@ -113,12 +114,15 @@ func DefaultQueryPlugins( channelKeeper types.ChannelKeeper, wasm wasmQueryKeeper, ) QueryPlugins { + // By default, we reject all stargate and gRPC queries. + // The chain needs to provide a querier plugin that only allows deterministic queries. return QueryPlugins{ Bank: BankQuerier(bank), Custom: NoCustomQuerier, IBC: IBCQuerier(wasm, channelKeeper), Staking: StakingQuerier(staking, distKeeper), Stargate: RejectStargateQuerier(), + Grpc: RejectGrpcQuerier, Wasm: WasmQuerier(wasm), Distribution: DistributionQuerier(distKeeper), } @@ -144,6 +148,9 @@ func (e QueryPlugins) Merge(o *QueryPlugins) QueryPlugins { if o.Stargate != nil { e.Stargate = o.Stargate } + if o.Grpc != nil { + e.Grpc = o.Grpc + } if o.Wasm != nil { e.Wasm = o.Wasm } @@ -167,6 +174,14 @@ func (e QueryPlugins) HandleQuery(ctx sdk.Context, caller sdk.AccAddress, req wa return e.Staking(ctx, req.Staking) case req.Stargate != nil: return e.Stargate(ctx, req.Stargate) + case req.Grpc != nil: + resp, err := e.Grpc(ctx, req.Grpc) + if err != nil { + return nil, err + } + // Marshalling the response here instead of inside the query + // plugin makes sure that the response is always protobuf encoded. + return proto.Marshal(resp) case req.Wasm != nil: return e.Wasm(ctx, req.Wasm) case req.Distribution != nil: @@ -317,6 +332,48 @@ func IBCQuerier(wasm contractMetaDataSource, channelKeeper types.ChannelKeeper) } } +func RejectGrpcQuerier(ctx sdk.Context, request *wasmvmtypes.GrpcQuery) (proto.Message, error) { + return nil, wasmvmtypes.UnsupportedRequest{Kind: "gRPC queries are disabled"} +} + +// AcceptListGrpcQuerier supports a preconfigured set of gRPC queries only. +// All arguments must be non nil. +// +// Warning: Chains need to test and maintain their accept list carefully. +// There were critical consensus breaking issues in the past with non-deterministic behavior in the SDK. +// +// These queries can be set via WithQueryPlugins option in the wasm keeper constructor: +// WithQueryPlugins(&QueryPlugins{Grpc: AcceptListGrpcQuerier(acceptList, queryRouter, codec)}) +func AcceptListGrpcQuerier(acceptList AcceptedQueries, queryRouter GRPCQueryRouter, codec codec.Codec) func(ctx sdk.Context, request *wasmvmtypes.GrpcQuery) (proto.Message, error) { + return func(ctx sdk.Context, request *wasmvmtypes.GrpcQuery) (proto.Message, error) { + protoResponse, accepted := acceptList[request.Path] + if !accepted { + return nil, wasmvmtypes.UnsupportedRequest{Kind: fmt.Sprintf("'%s' path is not allowed from the contract", request.Path)} + } + + handler := queryRouter.Route(request.Path) + if handler == nil { + return nil, wasmvmtypes.UnsupportedRequest{Kind: fmt.Sprintf("No route to query '%s'", request.Path)} + } + + res, err := handler(ctx, &abci.RequestQuery{ + Data: request.Data, + Path: request.Path, + }) + if err != nil { + return nil, err + } + + // decode the query response into the expected protobuf message + err = codec.Unmarshal(res.Value, protoResponse) + if err != nil { + return nil, err + } + + return protoResponse, nil + } +} + // RejectStargateQuerier rejects all stargate queries func RejectStargateQuerier() func(ctx sdk.Context, request *wasmvmtypes.StargateQuery) ([]byte, error) { return func(ctx sdk.Context, request *wasmvmtypes.StargateQuery) ([]byte, error) { @@ -324,10 +381,10 @@ func RejectStargateQuerier() func(ctx sdk.Context, request *wasmvmtypes.Stargate } } -// AcceptedStargateQueries define accepted Stargate queries as a map with path as key and response type as value. +// AcceptedQueries define accepted Stargate or gRPC queries as a map with path as key and response type as value. // For example: // acceptList["/cosmos.auth.v1beta1.Query/Account"]= &authtypes.QueryAccountResponse{} -type AcceptedStargateQueries map[string]proto.Message +type AcceptedQueries map[string]proto.Message // AcceptListStargateQuerier supports a preconfigured set of stargate queries only. // All arguments must be non nil. @@ -335,9 +392,9 @@ type AcceptedStargateQueries map[string]proto.Message // Warning: Chains need to test and maintain their accept list carefully. // There were critical consensus breaking issues in the past with non-deterministic behavior in the SDK. // -// This queries can be set via WithQueryPlugins option in the wasm keeper constructor: +// These queries can be set via WithQueryPlugins option in the wasm keeper constructor: // WithQueryPlugins(&QueryPlugins{Stargate: AcceptListStargateQuerier(acceptList, queryRouter, codec)}) -func AcceptListStargateQuerier(acceptList AcceptedStargateQueries, queryRouter GRPCQueryRouter, codec codec.Codec) func(ctx sdk.Context, request *wasmvmtypes.StargateQuery) ([]byte, error) { +func AcceptListStargateQuerier(acceptList AcceptedQueries, queryRouter GRPCQueryRouter, codec codec.Codec) func(ctx sdk.Context, request *wasmvmtypes.StargateQuery) ([]byte, error) { return func(ctx sdk.Context, request *wasmvmtypes.StargateQuery) ([]byte, error) { protoResponse, accepted := acceptList[request.Path] if !accepted { diff --git a/x/wasm/keeper/query_plugins_test.go b/x/wasm/keeper/query_plugins_test.go index 05559e7ee8..1fea83a25f 100644 --- a/x/wasm/keeper/query_plugins_test.go +++ b/x/wasm/keeper/query_plugins_test.go @@ -576,7 +576,7 @@ func TestAcceptListStargateQuerier(t *testing.T) { require.NoError(t, err) addrs := app.AddTestAddrsIncremental(wasmApp, ctx, 2, sdkmath.NewInt(1_000_000)) - accepted := keeper.AcceptedStargateQueries{ + accepted := keeper.AcceptedQueries{ "/cosmos.auth.v1beta1.Query/Account": &authtypes.QueryAccountResponse{}, "/no/route/to/this": &authtypes.QueryAccountResponse{}, } From 4f8d5137b27d53e9e4735b80f135178a239697b9 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Wed, 21 Feb 2024 14:47:56 +0100 Subject: [PATCH 32/45] Fix spelling --- x/wasm/keeper/query_plugins.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/wasm/keeper/query_plugins.go b/x/wasm/keeper/query_plugins.go index ee62da2f51..2bb2246968 100644 --- a/x/wasm/keeper/query_plugins.go +++ b/x/wasm/keeper/query_plugins.go @@ -179,7 +179,7 @@ func (e QueryPlugins) HandleQuery(ctx sdk.Context, caller sdk.AccAddress, req wa if err != nil { return nil, err } - // Marshalling the response here instead of inside the query + // Marshaling the response here instead of inside the query // plugin makes sure that the response is always protobuf encoded. return proto.Marshal(resp) case req.Wasm != nil: From 4c2d28a725e436b8c64332d6eac1813c57bdfbd9 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Mon, 26 Feb 2024 11:34:49 +0100 Subject: [PATCH 33/45] Remove unnecessary comments --- tests/e2e/group_test.go | 1 - tests/e2e/reflect_helper.go | 2 -- 2 files changed, 3 deletions(-) diff --git a/tests/e2e/group_test.go b/tests/e2e/group_test.go index 2cda127a74..49ab9638bb 100644 --- a/tests/e2e/group_test.go +++ b/tests/e2e/group_test.go @@ -122,7 +122,6 @@ func TestGroupWithNewReflectContract(t *testing.T) { var groupRsp group.MsgSubmitProposalResponse require.NoError(t, chain.Codec.Unmarshal(execRsp.Data, &groupRsp)) - // require.NotEmpty(t, groupRsp.ProposalId) // and coins received recipientBalance := chain.Balance(recipientAddr, sdk.DefaultBondDenom) diff --git a/tests/e2e/reflect_helper.go b/tests/e2e/reflect_helper.go index 44235eab3b..f73aa1112f 100644 --- a/tests/e2e/reflect_helper.go +++ b/tests/e2e/reflect_helper.go @@ -60,8 +60,6 @@ func MustExecViaStargateReflectContract[T sdkMessageType](t *testing.T, chain *i // build the complete reflect message reflectSendBz := []byte(fmt.Sprintf("{\"reflect_msg\":{\"msgs\":%s}}", vmMsgs)) - // {"reflect_msg":{"msgs":[{"stargate":{"type_url":"mytype","value":"EjQ="}}]}} - t.Log(string(reflectSendBz)) execMsg := &types.MsgExecuteContract{ Sender: chain.SenderAccount.GetAddress().String(), From 5dc97d5c0d9fdd07371d1726a0449686fb92148c Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Mon, 26 Feb 2024 11:35:51 +0100 Subject: [PATCH 34/45] Rename reflect.wasm to stargate_reflect.wasm --- tests/e2e/reflect_helper.go | 2 +- x/wasm/ibc_integration_test.go | 2 +- x/wasm/ibc_reflect_test.go | 4 ++-- x/wasm/keeper/msg_server_integration_test.go | 2 +- x/wasm/keeper/snapshotter_integration_test.go | 6 +++--- x/wasm/keeper/test_common.go | 2 +- .../{reflect.wasm => stargate_reflect.wasm} | Bin 7 files changed, 9 insertions(+), 9 deletions(-) rename x/wasm/keeper/testdata/{reflect.wasm => stargate_reflect.wasm} (100%) diff --git a/tests/e2e/reflect_helper.go b/tests/e2e/reflect_helper.go index f73aa1112f..095413e254 100644 --- a/tests/e2e/reflect_helper.go +++ b/tests/e2e/reflect_helper.go @@ -21,7 +21,7 @@ import ( // InstantiateStargateReflectContract stores and instantiates a pre 2.0 reflect contract instance. // This instance still expects the old CosmosMsg.Stargate variant instead of the new CosmosMsg.Any. func InstantiateStargateReflectContract(t *testing.T, chain *ibctesting.TestChain) sdk.AccAddress { - codeID := chain.StoreCodeFile("../../x/wasm/keeper/testdata/reflect.wasm").CodeID + codeID := chain.StoreCodeFile("../../x/wasm/keeper/testdata/stargate_reflect.wasm").CodeID contractAddr := chain.InstantiateContract(codeID, []byte(`{}`)) require.NotEmpty(t, contractAddr) return contractAddr diff --git a/x/wasm/ibc_integration_test.go b/x/wasm/ibc_integration_test.go index 8bcd2c3190..ea0a5f1730 100644 --- a/x/wasm/ibc_integration_test.go +++ b/x/wasm/ibc_integration_test.go @@ -194,7 +194,7 @@ func TestOnIBCPacketReceive(t *testing.T) { myMockContractAddr := chainA.SeedNewContractInstance() // setups env but uses mock contract // setup chain B contracts - reflectID := chainB.StoreCodeFile("./keeper/testdata/reflect.wasm").CodeID + reflectID := chainB.StoreCodeFile("./keeper/testdata/stargate_reflect.wasm").CodeID initMsg, err := json.Marshal(wasmkeeper.IBCReflectInitMsg{ReflectCodeID: reflectID}) require.NoError(t, err) codeID := chainB.StoreCodeFile("./keeper/testdata/ibc_reflect.wasm").CodeID diff --git a/x/wasm/ibc_reflect_test.go b/x/wasm/ibc_reflect_test.go index 2d847f8f1a..4d4670e459 100644 --- a/x/wasm/ibc_reflect_test.go +++ b/x/wasm/ibc_reflect_test.go @@ -16,7 +16,7 @@ import ( func TestIBCReflectContract(t *testing.T) { // scenario: // chain A: ibc_reflect_send.wasm - // chain B: reflect.wasm + ibc_reflect.wasm + // chain B: stargate_reflect.wasm + ibc_reflect.wasm // // Chain A "ibc_reflect_send" sends a IBC packet "on channel connect" event to chain B "ibc_reflect" // "ibc_reflect" sends a submessage to "reflect" which is returned as submessage. @@ -32,7 +32,7 @@ func TestIBCReflectContract(t *testing.T) { codeID := chainA.StoreCodeFile("./keeper/testdata/ibc_reflect_send.wasm").CodeID sendContractAddr := chainA.InstantiateContract(codeID, initMsg) - reflectID := chainB.StoreCodeFile("./keeper/testdata/reflect.wasm").CodeID + reflectID := chainB.StoreCodeFile("./keeper/testdata/stargate_reflect.wasm").CodeID initMsg = wasmkeeper.IBCReflectInitMsg{ ReflectCodeID: reflectID, }.GetBytes(t) diff --git a/x/wasm/keeper/msg_server_integration_test.go b/x/wasm/keeper/msg_server_integration_test.go index 06881bead0..614e0d3905 100644 --- a/x/wasm/keeper/msg_server_integration_test.go +++ b/x/wasm/keeper/msg_server_integration_test.go @@ -20,7 +20,7 @@ import ( "github.com/CosmWasm/wasmd/x/wasm/types" ) -//go:embed testdata/reflect.wasm +//go:embed testdata/stargate_reflect.wasm var wasmContract []byte //go:embed testdata/hackatom.wasm diff --git a/x/wasm/keeper/snapshotter_integration_test.go b/x/wasm/keeper/snapshotter_integration_test.go index eb216285c3..aff8591942 100644 --- a/x/wasm/keeper/snapshotter_integration_test.go +++ b/x/wasm/keeper/snapshotter_integration_test.go @@ -30,13 +30,13 @@ func TestSnapshotter(t *testing.T) { wasmFiles []string }{ "single contract": { - wasmFiles: []string{"./testdata/reflect.wasm"}, + wasmFiles: []string{"./testdata/stargate_reflect.wasm"}, }, "multiple contract": { - wasmFiles: []string{"./testdata/reflect.wasm", "./testdata/burner.wasm", "./testdata/reflect.wasm"}, + wasmFiles: []string{"./testdata/stargate_reflect.wasm", "./testdata/burner.wasm", "./testdata/stargate_reflect.wasm"}, }, "duplicate contracts": { - wasmFiles: []string{"./testdata/reflect.wasm", "./testdata/reflect.wasm"}, + wasmFiles: []string{"./testdata/stargate_reflect.wasm", "./testdata/stargate_reflect.wasm"}, }, } for name, spec := range specs { diff --git a/x/wasm/keeper/test_common.go b/x/wasm/keeper/test_common.go index 15a6aa8942..dbf52df037 100644 --- a/x/wasm/keeper/test_common.go +++ b/x/wasm/keeper/test_common.go @@ -679,7 +679,7 @@ type ExampleInstance struct { Deposit sdk.Coins } -// InstantiateReflectExampleContract load and instantiate the "./testdata/reflect.wasm" contract +// InstantiateReflectExampleContract load and instantiate the "./testdata/reflect_2_0.wasm" contract func InstantiateReflectExampleContract(t testing.TB, ctx sdk.Context, keepers TestKeepers) ExampleInstance { example := StoreReflectContract(t, ctx, keepers) initialAmount := sdk.NewCoins(sdk.NewInt64Coin("denom", 100)) diff --git a/x/wasm/keeper/testdata/reflect.wasm b/x/wasm/keeper/testdata/stargate_reflect.wasm similarity index 100% rename from x/wasm/keeper/testdata/reflect.wasm rename to x/wasm/keeper/testdata/stargate_reflect.wasm From 77504d856297680befebdb5a8e6a34bc21076dd6 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Mon, 26 Feb 2024 11:41:09 +0100 Subject: [PATCH 35/45] Cleanup --- tests/e2e/reflect_helper.go | 1 - x/wasm/keeper/handler_plugin_encoders_test.go | 7 +------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/tests/e2e/reflect_helper.go b/tests/e2e/reflect_helper.go index 095413e254..0650211e8a 100644 --- a/tests/e2e/reflect_helper.go +++ b/tests/e2e/reflect_helper.go @@ -60,7 +60,6 @@ func MustExecViaStargateReflectContract[T sdkMessageType](t *testing.T, chain *i // build the complete reflect message reflectSendBz := []byte(fmt.Sprintf("{\"reflect_msg\":{\"msgs\":%s}}", vmMsgs)) - t.Log(string(reflectSendBz)) execMsg := &types.MsgExecuteContract{ Sender: chain.SenderAccount.GetAddress().String(), Contract: contractAddr.String(), diff --git a/x/wasm/keeper/handler_plugin_encoders_test.go b/x/wasm/keeper/handler_plugin_encoders_test.go index 2fa633018d..f5536a3355 100644 --- a/x/wasm/keeper/handler_plugin_encoders_test.go +++ b/x/wasm/keeper/handler_plugin_encoders_test.go @@ -430,9 +430,8 @@ func TestEncoding(t *testing.T) { encodingConfig := MakeEncodingConfig(t) for name, tc := range cases { t.Run(name, func(t *testing.T) { - var ctx sdk.Context encoder := DefaultEncoders(encodingConfig.Codec, wasmtesting.MockIBCTransferKeeper{}) - res, err := encoder.Encode(ctx, tc.sender, "", tc.srcMsg) + res, err := encoder.Encode(sdk.Context{}, tc.sender, "", tc.srcMsg) if tc.expError { assert.Error(t, err) return @@ -448,10 +447,6 @@ func TestEncodeIbcMsg(t *testing.T) { addr1 = RandomAccountAddress(t) addr2 = RandomAccountAddress(t) ) - valAddr := make(sdk.ValAddress, types.SDKAddrLen) - valAddr[0] = 12 - valAddr2 := make(sdk.ValAddress, types.SDKAddrLen) - valAddr2[1] = 123 cases := map[string]struct { sender sdk.AccAddress From 8663a859939b774a443831586c903e3847abd60f Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Mon, 26 Feb 2024 16:42:54 +0100 Subject: [PATCH 36/45] Add msgResponses in IBCRawPacketHandler --- x/wasm/keeper/handler_plugin.go | 9 ++++++--- x/wasm/keeper/handler_plugin_test.go | 3 ++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/x/wasm/keeper/handler_plugin.go b/x/wasm/keeper/handler_plugin.go index 2fc1f9c276..50bd1a1b67 100644 --- a/x/wasm/keeper/handler_plugin.go +++ b/x/wasm/keeper/handler_plugin.go @@ -197,15 +197,18 @@ func (h IBCRawPacketHandler) DispatchMsg(ctx sdk.Context, _ sdk.AccAddress, cont } moduleLogger(ctx).Debug("ibc packet set", "seq", seq) - var msgResponse [][]*codectypes.Any resp := &types.MsgIBCSendResponse{Sequence: seq} val, err := resp.Marshal() if err != nil { return nil, nil, nil, errorsmod.Wrap(err, "failed to marshal IBC send response") } - // TODO: fill msgResponse + any, err := codectypes.NewAnyWithValue(resp) + if err != nil { + return nil, nil, nil, errorsmod.Wrap(err, "failed to convert IBC send response to Any") + } + msgResponses := [][]*codectypes.Any{{any}} - return nil, [][]byte{val}, msgResponse, nil + return nil, [][]byte{val}, msgResponses, nil } var _ Messenger = MessageHandlerFunc(nil) diff --git a/x/wasm/keeper/handler_plugin_test.go b/x/wasm/keeper/handler_plugin_test.go index ba20f4a9b1..01d23ccd39 100644 --- a/x/wasm/keeper/handler_plugin_test.go +++ b/x/wasm/keeper/handler_plugin_test.go @@ -321,7 +321,8 @@ func TestIBCRawPacketHandler(t *testing.T) { assert.Nil(t, evts) require.NotNil(t, data) - require.Len(t, msgResponses, 0) + assert.Len(t, msgResponses, 1) + assert.Equal(t, "/cosmwasm.wasm.v1.MsgIBCSendResponse", msgResponses[0][0].TypeUrl) expMsg := types.MsgIBCSendResponse{Sequence: 1} From e982aabcc00908002e9b66a79dd6f3d53a988bbd Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Mon, 26 Feb 2024 16:55:23 +0100 Subject: [PATCH 37/45] Apply suggestions from code review Co-authored-by: Simon Warta <2603011+webmaster128@users.noreply.github.com> --- x/wasm/keeper/api.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x/wasm/keeper/api.go b/x/wasm/keeper/api.go index ed547b1fef..4c9343c978 100644 --- a/x/wasm/keeper/api.go +++ b/x/wasm/keeper/api.go @@ -17,7 +17,7 @@ const ( // DefaultGasCostCanonicalAddress is how much SDK gas we charge to convert to a canonical address format DefaultGasCostCanonicalAddress = 4 // DefaultGasCostValidateAddress is how much SDK gas we charge to validate an address - DefaultGasCostValidateAddress = 9 + DefaultGasCostValidateAddress = DefaultGasCostHumanAddress + DefaultGasCostCanonicalAddress // DefaultDeserializationCostPerByte The formula should be `len(data) * deserializationCostPerByte` DefaultDeserializationCostPerByte = 1 @@ -54,7 +54,7 @@ func validateAddress(human string) (uint64, error) { if canonicalized.String() != human { return costValidate, errors.New("address not normalized") } - return costValidate, err + return costValidate, nil } var cosmwasmAPI = wasmvm.GoAPI{ From f41bb6f9dc591dbcdf6fc1d786f22fad2edac621 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Mon, 26 Feb 2024 18:44:27 +0100 Subject: [PATCH 38/45] Fix costValidate --- x/wasm/keeper/api.go | 2 +- x/wasm/keeper/keeper_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x/wasm/keeper/api.go b/x/wasm/keeper/api.go index 4c9343c978..c25a63860c 100644 --- a/x/wasm/keeper/api.go +++ b/x/wasm/keeper/api.go @@ -26,7 +26,7 @@ const ( var ( costHumanize = DefaultGasCostHumanAddress * types.DefaultGasMultiplier costCanonical = DefaultGasCostCanonicalAddress * types.DefaultGasMultiplier - costValidate = DefaultGasCostCanonicalAddress * types.DefaultGasMultiplier + costValidate = DefaultGasCostValidateAddress * types.DefaultGasMultiplier costJSONDeserialization = wasmvmtypes.UFraction{ Numerator: DefaultDeserializationCostPerByte * types.DefaultGasMultiplier, Denominator: 1, diff --git a/x/wasm/keeper/keeper_test.go b/x/wasm/keeper/keeper_test.go index e6811c55f7..084d8d982f 100644 --- a/x/wasm/keeper/keeper_test.go +++ b/x/wasm/keeper/keeper_test.go @@ -421,7 +421,7 @@ func TestInstantiate(t *testing.T) { gasAfter := ctx.GasMeter().GasConsumed() if types.EnableGasVerification { - require.Equal(t, uint64(0x1bc5a), gasAfter-gasBefore) + require.Equal(t, uint64(0x1bc64), gasAfter-gasBefore) } // ensure it is stored properly From 8607164e87ef5120970c62a652e56357087182f2 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Mon, 26 Feb 2024 18:45:49 +0100 Subject: [PATCH 39/45] Add validateAddress test --- x/wasm/keeper/api_test.go | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 x/wasm/keeper/api_test.go diff --git a/x/wasm/keeper/api_test.go b/x/wasm/keeper/api_test.go new file mode 100644 index 0000000000..752ac1dc4a --- /dev/null +++ b/x/wasm/keeper/api_test.go @@ -0,0 +1,34 @@ +package keeper + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestValidateAddress(t *testing.T) { + specs := map[string]struct { + human string + valid bool + }{ + "valid address": { + human: RandomBech32AccountAddress(t), + valid: true, + }, + "invalid address": { + human: "cosmos1invalid", + valid: false, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + _, err := validateAddress(spec.human) + + if spec.valid { + require.NoError(t, err) + } else { + require.Error(t, err) + } + }) + } +} From 044caabe9e4af212fb94ddffaa74bdeab66772d3 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Tue, 27 Feb 2024 17:20:04 +0100 Subject: [PATCH 40/45] Update capability table --- README.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index d28d405bd4..6b59332236 100644 --- a/README.md +++ b/README.md @@ -28,16 +28,16 @@ Also CosmWasm 2.0 contracts remain compatible at the Wasm interface level. To extend the feature set over time, contracts can specify required [capabilities](https://github.com/CosmWasm/cosmwasm/blob/main/docs/CAPABILITIES.md) through cargo features in cosmwasm-std. The following table shows which of the [latest capabilities](https://github.com/CosmWasm/cosmwasm/blob/main/docs/CAPABILITIES-BUILT-IN.md) are supported by certain wasmd versions. -| capability | >= 0.42 | >= 0.41 | >= 0.31 | >= 0.29 | 0.28 | -| ------------ | ------- | ------- | ------- | ------- | ---- | -| iterator | x | x | x | x | x | -| stargate | x | x | x | x | x | -| staking | x | x | x | x | x | -| cosmwasm_1_1 | x | x | x | x | | -| cosmwasm_1_2 | x | x | x | | | -| cosmwasm_1_3 | x | x | | | | -| cosmwasm_1_4 | x | | | | | -| cosmwasm_2_0 | | | | | | +| capability | >= 0.51 | >= 0.42 | >= 0.41 | >= 0.31 | >= 0.29 | 0.28 | +| ------------ | ------- | ------- | ------- | ------- | ------- | ---- | +| iterator | x | x | x | x | x | x | +| stargate | x | x | x | x | x | x | +| staking | x | x | x | x | x | x | +| cosmwasm_1_1 | x | x | x | x | x | | +| cosmwasm_1_2 | x | x | x | x | | | +| cosmwasm_1_3 | x | x | x | | | | +| cosmwasm_1_4 | x | x | | | | | +| cosmwasm_2_0 | x | | | | | | ### For node developers From 1ee2c4913647f803324da7765b1c3251eb1ed3d7 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Tue, 27 Feb 2024 17:38:17 +0100 Subject: [PATCH 41/45] Use reflect contract from 1.5 --- tests/e2e/reflect_helper.go | 4 ++-- x/wasm/ibc_integration_test.go | 2 +- x/wasm/ibc_reflect_test.go | 4 ++-- x/wasm/keeper/msg_server_integration_test.go | 2 +- x/wasm/keeper/snapshotter_integration_test.go | 6 +++--- x/wasm/keeper/testdata/reflect_1_5.wasm | Bin 0 -> 330270 bytes x/wasm/keeper/testdata/stargate_reflect.wasm | Bin 311871 -> 0 bytes 7 files changed, 9 insertions(+), 9 deletions(-) create mode 100644 x/wasm/keeper/testdata/reflect_1_5.wasm delete mode 100644 x/wasm/keeper/testdata/stargate_reflect.wasm diff --git a/tests/e2e/reflect_helper.go b/tests/e2e/reflect_helper.go index 0650211e8a..f857c8dad0 100644 --- a/tests/e2e/reflect_helper.go +++ b/tests/e2e/reflect_helper.go @@ -18,10 +18,10 @@ import ( "github.com/CosmWasm/wasmd/x/wasm/types" ) -// InstantiateStargateReflectContract stores and instantiates a pre 2.0 reflect contract instance. +// InstantiateStargateReflectContract stores and instantiates the reflect contract shipped with CosmWasm 1.5.3. // This instance still expects the old CosmosMsg.Stargate variant instead of the new CosmosMsg.Any. func InstantiateStargateReflectContract(t *testing.T, chain *ibctesting.TestChain) sdk.AccAddress { - codeID := chain.StoreCodeFile("../../x/wasm/keeper/testdata/stargate_reflect.wasm").CodeID + codeID := chain.StoreCodeFile("../../x/wasm/keeper/testdata/reflect_1_5.wasm").CodeID contractAddr := chain.InstantiateContract(codeID, []byte(`{}`)) require.NotEmpty(t, contractAddr) return contractAddr diff --git a/x/wasm/ibc_integration_test.go b/x/wasm/ibc_integration_test.go index ea0a5f1730..d268a8c720 100644 --- a/x/wasm/ibc_integration_test.go +++ b/x/wasm/ibc_integration_test.go @@ -194,7 +194,7 @@ func TestOnIBCPacketReceive(t *testing.T) { myMockContractAddr := chainA.SeedNewContractInstance() // setups env but uses mock contract // setup chain B contracts - reflectID := chainB.StoreCodeFile("./keeper/testdata/stargate_reflect.wasm").CodeID + reflectID := chainB.StoreCodeFile("./keeper/testdata/reflect_1_5.wasm").CodeID initMsg, err := json.Marshal(wasmkeeper.IBCReflectInitMsg{ReflectCodeID: reflectID}) require.NoError(t, err) codeID := chainB.StoreCodeFile("./keeper/testdata/ibc_reflect.wasm").CodeID diff --git a/x/wasm/ibc_reflect_test.go b/x/wasm/ibc_reflect_test.go index 4d4670e459..c73155da9e 100644 --- a/x/wasm/ibc_reflect_test.go +++ b/x/wasm/ibc_reflect_test.go @@ -16,7 +16,7 @@ import ( func TestIBCReflectContract(t *testing.T) { // scenario: // chain A: ibc_reflect_send.wasm - // chain B: stargate_reflect.wasm + ibc_reflect.wasm + // chain B: reflect_1_5.wasm + ibc_reflect.wasm // // Chain A "ibc_reflect_send" sends a IBC packet "on channel connect" event to chain B "ibc_reflect" // "ibc_reflect" sends a submessage to "reflect" which is returned as submessage. @@ -32,7 +32,7 @@ func TestIBCReflectContract(t *testing.T) { codeID := chainA.StoreCodeFile("./keeper/testdata/ibc_reflect_send.wasm").CodeID sendContractAddr := chainA.InstantiateContract(codeID, initMsg) - reflectID := chainB.StoreCodeFile("./keeper/testdata/stargate_reflect.wasm").CodeID + reflectID := chainB.StoreCodeFile("./keeper/testdata/reflect_1_5.wasm").CodeID initMsg = wasmkeeper.IBCReflectInitMsg{ ReflectCodeID: reflectID, }.GetBytes(t) diff --git a/x/wasm/keeper/msg_server_integration_test.go b/x/wasm/keeper/msg_server_integration_test.go index 614e0d3905..fad2b112b6 100644 --- a/x/wasm/keeper/msg_server_integration_test.go +++ b/x/wasm/keeper/msg_server_integration_test.go @@ -20,7 +20,7 @@ import ( "github.com/CosmWasm/wasmd/x/wasm/types" ) -//go:embed testdata/stargate_reflect.wasm +//go:embed testdata/reflect_1_5.wasm var wasmContract []byte //go:embed testdata/hackatom.wasm diff --git a/x/wasm/keeper/snapshotter_integration_test.go b/x/wasm/keeper/snapshotter_integration_test.go index aff8591942..ed9af49f99 100644 --- a/x/wasm/keeper/snapshotter_integration_test.go +++ b/x/wasm/keeper/snapshotter_integration_test.go @@ -30,13 +30,13 @@ func TestSnapshotter(t *testing.T) { wasmFiles []string }{ "single contract": { - wasmFiles: []string{"./testdata/stargate_reflect.wasm"}, + wasmFiles: []string{"./testdata/reflect_1_5.wasm"}, }, "multiple contract": { - wasmFiles: []string{"./testdata/stargate_reflect.wasm", "./testdata/burner.wasm", "./testdata/stargate_reflect.wasm"}, + wasmFiles: []string{"./testdata/reflect_1_5.wasm", "./testdata/burner.wasm", "./testdata/reflect_1_5.wasm"}, }, "duplicate contracts": { - wasmFiles: []string{"./testdata/stargate_reflect.wasm", "./testdata/stargate_reflect.wasm"}, + wasmFiles: []string{"./testdata/reflect_1_5.wasm", "./testdata/reflect_1_5.wasm"}, }, } for name, spec := range specs { diff --git a/x/wasm/keeper/testdata/reflect_1_5.wasm b/x/wasm/keeper/testdata/reflect_1_5.wasm new file mode 100644 index 0000000000000000000000000000000000000000..073a4f40645c73eb36895584a88c5eea0fde6478 GIT binary patch literal 330270 zcmeFaeb`-BS?9lB&fD{x=Oic1OP?mC-RBVWNom>uB?+Z-nVo59xxo2##{PlV#Y|gi z#x^N^2?b$B+jJ-;AYjmfL93=tu|)x^zdDw&GX|*=1hpta918^KV9_E~`*Xrj;rIF8 z_geex^Smc5GtM;<`s{u7UN85$*ZsckwRUpV>t35CNs>O2Zn!eL_15%O{Y|dSZ;gL> zlJX$cs|HWGZ|cIeWmj%GexqlUyCoE$LXuqB4)6G-M&sLC618@VU#wqRyM_OaY8Vv! zPE_?4HQtT=sG(c0Tv7Y!PqJGaOtq8!Z90|jzWxpEtAFTx^I%(=xhhIOk@7kMp zC#il;*vr@6@P^$ttFFJ{`fFdqn}4@ENk(O_ zdHrjzy1shWf8Fla-1x#5Z{7QXE8ehs-?jhtO-Zhz)1$}xcE5(+_FZw~>wjqP?l&bX z^m@hat6%uy7r)>oV|CWVhd*@H&9Av;>{avX-9PmDA9jelH@$xMzBgU*nrp7Q_Ilv` zZ`rYIWtwH3tkY>{N!rfZnf}+$TCH{~%~Ji}{%f?jNz+E!Zs>2;%DkvOvp)^1$sezv zQYxB3FAe`6cX{5*XwQna@|-8D_;2q28jbX{1X81yG*N^4$6eM)n~hdGn`*VPiPaMm zSu1H8MP`kLy-iaCRPZ&{=)N^c{bX{oK_^WhS_@G8ubnjgfBFH8{=)#tvsOB#-e@q( z@=PPhlUCN%O*>zgboD#Ql5RVvUhnkjyxHUd4JEzo47HKv`T9mPy)oUlubHRGs@56# zt!cS`|BJ3=SN4^_D^K})@yga_J)0LqQz^kf8EVjU4QenBBwjj_UxBJHH-jp0jn>K^V+tSWe*IjqRYgF)|bn@!m)vy1OuG+Wzrq^G)Z};o2ps{^F ztRf#x`}K!=uf6_`B_u3zUyRUe`6)#-q#fuhtalt|_Ucigh*Is|~?tTCE zs@LomQNHfl8?L`%JC7%?xB{NJ>WbahU!AAjE3UX^_fu&h3>2Ie;(%(rxmOh;RZu)!a$J3+fC(_?fU-F0PP5AmT@)4S96XTO;K zQTkKqPo(cm?@Zs5{$%>o>ATYF9!WoweI)yOdfg4*NdG#0BK-%dJeB@`=}mvbkH1U5 zoqi|XpWTMAxZ&rrpUv*d4rM=+y)XNv>^HLqvtQ5tB)j2n)8EQ|J3EqnA^T|dJK4vw z&u3rECcm|R^|9(yrYNJGvw< z(~F|h@A>NvFN;o@?iseWW>%t6boP|zUYI1^A}x~(lZI6*T3)dgE4HlFM$y_+4k=74 zt*VtgRN4Cq>#SAe{T1Hbs8*5j^vl_LD&{m&b)OWiy=D6SUa`#PRxE$PeYw%@U2iU3T{H=gd6}f0**HXcz5G*_vTvTb@vEYENNL zlcKRLYw$q7RIS*vG3kCHP4j@{Y-5t`5Pmh%bXSkcYBDd=n}>}e|6H{=YA>nXEC$bxCYc z5mH)cOl7Lnv0)|UZTt7{f8)z~X^{x9yh!?o8AbnY4JGrTd=j}7hLXpj&{@V{UJ(Za zj7twDV=#gZ8%*wlc~>`U+?w42 z`R`Bn4jYmFbIp&_KmBwDO`%qIL&%VhMaB>uWNfb?NPcNPn<6Ei8A*@Pzp52Yuh@(g zo7O7K5$GS9ueU;ly=6;etQT#_*t#3lf;hg6@SaJMtqH7K=6lNjKKgByMle}x#uR!X zrkK@QWD0w2OwlMGN%p{Ef0>G8K}usLyG$g+^>QexQ65Y7Y(|j+q2mc^(%mrCCEzKI z!xa*p?nih^T}}wW4Y-Rxk0wsfa8l9OlwH0pTNBWKY6xsZ1UBam83g{)Z8Zco_LRTO zZ-yjsBt$fy2?D`bwkhvlCXAI^gvq~1olA>7oAPAPhN-6Qu0w$lu19z_OmEE!;UXaW z!enD8+<=J7j{z^jqSK$UTJWy7WG_Fdm#v~5UfR?N5ay32HzynWU&6i=>Mxof^%w98 z7TqE-v2-Du#3fpyotbQlATdHga#w^hA76-xY$9shb!v3biF7bAFCF{}sM?ey+vpC# zyQlnr$LV0=nbCn$LNbRE8WM4r7LA<<-u?Y;xd;V1fPWh0j=kjr2ahEEhclDVMcO}> z+4PE%gvE>X=hFU{DLj+yki^!*{?nQUaBNg(EOpTsM_nL}vPnnfA!DHdmGAeYOibV9 z-SSiPTy6u36UmfBcK3N@+sOscC%W8yW#_G~rTuB*ug@>hED zcN@s#RPuPoo?$17<2Kj};uyso%n{uUC#0!O%(ROM#EiY3KPPQ!q!=q9pIEic#{~Ym>Yk zacR5%H50r=CvZ%s+%9oDXn~N93>IEo0If6|w@Osqj7V;k-$`%UHE2Oe0Dlv}V$n%& z$*`09No~A(IAFZ|Vu;dOJgI3d>mPHZzsfp?G$c<32!jDbm$8`ll5Uw`v31pBnOxHU zN~*GBWCWBDU@XQ5@pG|hZOR-qZFXTY<>h5clz%D_+C(O-5iDG%b?u*~ zir$1!i9xbCnF75SS)D;c?4`S5)2uGxJu4*M>@^CUUm~rBdghs#01|bQvp~BkyLdD# zxDx9!FFzF(zxGuR%Q;Tl9#*jqLwGWDVb%^K*VTEk}f zt^JkiY+|^T-{JT9i5b>bX*51-&1?_75C_a^EpmXpHhKj1t=aY>kCJhV&B?IAWy_vQ zFe1772UDaXG`UCo2Se!3c1cC95`ubWLXn$7lb#??CH2g#U_PmQ?ugKGp?~ABwJq;E z=4HuKr!|@pVfM)cfwi&{lzI9196|XPIQve9@Jl7l#JoY8wL~m!fuTF385d*HmPs>v zjWpwzrlu`o;n`eirfNl76D(cdv(^S}Yqe3d!vyoHY6UrARZN=k!lapXH>xFUnsWui z(@51lJq2l|7B!c%D#p3A*Fl;gt6JDFO{Rt6OH9~AxVkY>aEknH?$y)(glO|(L2W~L zHQmq(#-{%W$nSm^uzyD$$$ZQI?J)#oP^14FDSQFJH>Kt`qMo_TNFH%5n4MI@hrK>!Q5%Vf*866i3!2e*n(fOrf-|+GFKfC9ky*0}LM(@eL7!lTB5wGN z&NI(%q)+4>Mt$NHf62NtaK&o+B%P&CtWwY?v9;jKx;~lJT9iSm=K-FkrbHrb z6{shOH4F7k863^J!O<+5itj9LxHdhGa5@UYLl;~vn8Gaoan}9&HQAJFfJcZg5cv>~-P^iYlK>pbdfwiKKBRT&brZeHVL>rv@>1u0eZiD$Dx2Z* zLtp_2Eh@&WLeRX4iT3+c{T)g#^7>)PZta0Nzl5s*HBxBVYu zClV8;2qOW1pj947uNz>=?o#Ma6jCN91APc*5s@^<5pc_`~gMX~;V z!imKRZ(>uHY|DPsEP0vHj7R;R62WAVU=+jl;Z$TcY?mLqqq3VZsP>e<%WvE~@ucV= zKV|wcE{ilW_X;OYW7jdNVXuU)n?A3mTNd|)U;sqIv46%C_UM9m zs3?UJMkzs3+1xkE<8Nl(ThfFsRj>%1@YLWud^o2$i7ALJh-ssh*z_;J^v!ak1P9j{ zUHj7>Ym;znl)nX1OGWgGJ^l5}c$AMP3Bo^UTBf=pnFnhmOC^6-GOPM`a>}6$& zjGihc1>tb=k`P%T3O902Mlj=iWhi;i$DjM|3|s&sX|kg)=V%){+JHxz;p zszT)#@Y_oTdp7#pT|H@xg>|i|;>R=?p`^k%s`^K_Wv_OcUAVSs>V;pMG~Qx}Lal60 zE)HngBA_HL3~44VSmZ+f>*2tufidhUjYFYyEwEu^h&b-E={MpSF>0QOPYeen)H z)#60B7YhROw)}|Te*b%zxc?crv;RCb{fNa;KTn206?tg6D6aWDQHOl37O9qwTbhjO5!P7UpSv60hIWsRqYgpvc0BQ+RU9_RZ!UOYw=R#N_ zM}ns1c=VZV6)^tdR=dSpPNkyyvv|YLkjCNYB}|=1^g?~io%EQZQUSe?Gr#KSB~a$* zRUiv0eN-}AILUVCpGB>t+6*&0^wis!@@13Y&1=sL?6&*bn znJx7eAUZY<5$3{D5QTnbL*%^)V+(Y*Q31Y+5$VPl@k}0~m8K=Gatwz>%P@;emcdkB zvJ51fLqf4HCs~JR*xZ&+7j;?G9QpXtoJ%!MiJ5GANy@31YBo_iQz1yT&~CknhRl93 z2+tIRorNG&HH*CyiwnF#G$=$NPGF^>3==&v z`aCcb+Qt9hI3xxi0yA6{n8{4wDmD-$(?b1JNSwWTQb{IRM~Kzh0>&twP>dn5wh$)C zbjpDUivhiNB4YnpkW62dWNKHE$>r0tBcUKIxfxlS7-gFv{DpVW-DD-BAiAX_!Ut3X z3&8C@u2W_S+1kvOo_r@7HW~GwVo6`c(Xu-rL}|t%bSz0DnAvO9^OpH#3Re75tT=_$ z5yafb#s+0VY6)4Rx=RiGsXG|Be0j5JW(|C~oz#X*not-rHs+F}!~P4S`vZ+m{)XXe zIUTF+cYSmbKutZ!sf|uFu>}52MV*R_wu(zM{;VpJ*~-;q_pFDY`yYc=I7kBTvt}`U zU2PX=3-Wgk?RtKGcufhQqi+B zB1p^OIn{keJh#ha=@Jl{9c6<2R|MgjlYvlmmxAz@KchinJZ{Q&oCKc6nz&oTT!^%mL#Sh|Raj?Hb@}>utckZB2msmA4imV= zVjAvgoHRhcq~R%sdqD(f*K%S377a1+@XJPuC&MnP`&}o42;eL-*nSdZFxEshaYPlC zKXGGCR1;?lcc9!?TbDm^W35$mIZg)AFIq;#V-&6W4b9<6iM-`Rs}|Kv%OTVVpv~c_ zO~63Y2w!V_&!X`ZB zBaN2Rl#gUFeg;gevA&#E<-;|U*u;9;`(*;m@crO5tmz(+B_*@m!*a=$y48|1RW3}f4pqp0AwT@LRL#_N*srDh1?9Y>Y#ZeVtHpF$ z*hFL7vNL&Xt5ncU?EAxN#5`c{n-$gA_sm$|=Y}c`t>=xp?j!mtgoK#+fNcmKSRqA> zmoo#>tXQ*S$m9npuMYrp$Et}EhP29wI%QhyH6*9VOiYyH8JZ;Q>?8WLjPWh66r90K zq(BRdSCTXVj8_8+h7Wr%lnJ9d66v`ZjJYM!+iM9;Po!t7Cb8zM|254OvK?t@Y69%!mz@R}VrVUuLyh9mepfiF>g}r6| z{ay#c3+c19T7UnAPyb3w+dx&bF{@@smCY>WaCU!TFSP1;s;mKt zDC(9h+zFOAkTznA&B=YrnY1k#xh6_?FfAABjuaxgv)6j*RA$MzJR32s&D|5pp5io@ z3d%ic6sK8E)zw|L!w$8W(!V5jTumvd z5`WF_u&2l>g(;1#*_7%U7J$!VeKz1gLONT!CL-X&3|X`-+F4X&xs^=zacNC7B5+MnbhYxdOrAD|M{~Y zda`#pIJRo0r$>cv`LV%j5%Zd2&FJC&;o8v;O4z1WB`*x7M$ZRpvmNF4 zl@BMyx;NcB?Cga-8!y{1?3dq3ZW?yVBgsvIt3wvy&V+a0chiT4Yws9UFL}6EPY>MA zKr7&jwRa5G65X#ovATB{Hr94Y=3A>R8&d_Uqq8$D`f7u>kdSZq=FkInh7V59B}3K~ z(?7=8PQUy^KgO7nA0TU!UyP_&U7T_I;EZCeVQ=kVomLdaP+$etQoIJ8;R3BRz4QC- zC{Ev*0{iK_PY=-lv@X+A92V0pR$o?c>vCa&0UiChpZlx#o@fnD=RW-J*1;JD=W2kW ztF?lY>32BS3eGc%^|ue!7h#r}thsPfU>-O{KuWo-eh(gD9%$+ifnJ<(FYbWmO;g^&^(DO7`;B?A6{MU|p#@60^2uui}aw@S|KX1#jkZ z{1;W_Mt^V}m%FTuYpeMdU+)*&E+ywR8vWI zbY`>74)j-nuugf;-E8)L*fpG`vSj`Ll8IC73>Kio{OTXICSNtsu5_K|!NXTu3e5_H zX?b431y$AOD5YK|`YENM@?o~ivXUqF45x^E4oMAD{`vIH<@D=^E6e0kT3QLaWVaSm zWj5#ij(@@XUU~LSBC)DmzEHW9RXJK~c&V~|Q`x$CU$^>0_xtxhoN(}oY{bdEpd|y; zUb#h&x(s@fjSfdMGIbNS`m&FtQA{#YQbfy#z!V$h4cX;W`tb;};~V8|q!m{B0IphH z(tR^Q-z=ZPCtyw!Zl50Aj;5EXVNxr?&?XO?S)R=pWiTC@-~K1E0phVKAub{}pJG4m z5NUZc*`0{_83aEo=DIm31Hm5KWO29Oo|Mw}jq)AiUdZiuA*S&g@?gk-jOPVh*=wQ= z&<<=)1!1eo>Ak~MA$2*cr!LdM4iIJrWZMnMX0>m&p}j0~4;XMz=5dIw7UCM(3(eno z-d|jQPb*NO+b%d%S8vNMu55K$sJ~;sb@a6;Qcsy!$XiTecB-rbc@+4TX0cU?bPa?8 zP+D}S=1`m|VKAOZS92!>peOOZGp|l&3MssaodOg#4+CV!Po~k`Qrlwe#1#rw+hTB} zWt^Mq2>r>FnYB?%g~!HT=N&97>xBi$`^RM2-}d!_A5lhdJnX%3CS z!W{3}`M1CS(XYJs8=w2lzqWm8R_dATr>vQFnQc>G4J&8U5N3ttSmx!gGv65bkJ|w= z;hFa4kxkAslUA@tUjCAvwe`$IqCLAimeW321n8`ZJmnloo5;_!;(q1hNfmEe?9j8e zKrrusExmXL{9@Za1N9weqeIWwYA;WrVl7oWsYB1a!rpR1p1w{)n`9=fJ6tZV+KUTo zy^F(HHq}_`z5EVNl2v*}C!zWALCtXX2>6E?&18uO5Dh#b*W@|xE@vY^j^B%Adz};~ zOK<4N)XyQ2gTZ+=a)DbIL+r`WenX9D$gYD5tJ=q5!xRaqlnGQDFxtU!8sYj&Q(~7% z#mU`$)rH9`bq64Jl8zmtgjS)`dzE$|i28dq5rn#QCFxTm!r$-~y=>UjMCioJjtT;A z1OGvieD2Xy7s(fHV5X_fO9js>!*M#>QI9f02U(d86thG<=0QDT0*rR{P;nad7{nB& zu=iHm%*3pl<9(61W-(a6UWi1^h4f5Uj25+FG>os(ix;8$RC57s)tRlWI(6x2W&yj; z|KJ}#SJ`nUVi1KMjNHb!>VG11X5vw5gdV=l?;2Od1ARobCx5#BCdLAqd(= z-#alOj6QADB5}-rN)ISl^uG*Roxb2+qqcwsFQk0*PZSgA^Y*b%=x&-jYhC)ZBM(su z07ayz!>lIE1&tNegjGz@dRw!N)X^4GYmvKixhw2hgS&H0U0d_Adb9@x#cV4jge(&7 zv_a4AbjBxYj+HHO zvdt{n%vO}W=l3YL`m~U{A;+HXu7*JER4d{$bgVczVGE)mx*KAXFf;NRA>$Y^r$rHU zT(_cxTo1F~rYv>Ed;2x@wj%aM6S>wubHyK=2nfRD=B`(p^pvq=K-rmK60j!D4o*M3qHm$Fewl*ng&Bw@!+P zVy?>K!wv`jEi^k-KJFr5T9OCLf{~>q2;TkQF2Dcyi_czpec3bJ4X3Y^B7qp+QVT8v8GN?14VeXJh@cP9Bv*AU>PZP z)}y7BOqk}7NK7s3z+S@w{1WCY;KQ@Atb^P<%Sb2EhX7}yPl64-yj?!uGD+@lHbQ+}A=hQfpq zQfV|oYt7<$dZCrsS*^v{wAbe9+a#b``yP;yJ)qIh(oWVwxL`v;G1mjf#Kby@%d=W*2y)ik+z;GP1@<_YETIv0zv1@*$_x^ z>6E`ZqREaDKz@Dn+bTVCn#3NobuW$Eae&+loT7s<>X>DQnub9G5D}P_AOB3nG+2~- z%1`p!nZ~T~dZU)zqgiguZd8VLSYALHKlRw3TA~l9@0z>_hM`ofEO(u2dJ-Z-fvv^F z4`PMWRAqUZ>d^8JI>)4qsi{#Y$pn`|N%mGjtz>a)bFi03FJ*?fg1a zg3u0Ul`>7;1SBpQPJ)Ay3E=cS`q&XATQE5UAp1H)G{adF{4yV zJG2FiXF}>c#~Gc;L*{;3?p*-sAMOAX=G|F~>?K*Sa;?^nzm-~c_=9SJumvl{9xLtQv^VeV1jK2X^XOJE6!6tML3f^21+xaEMNx=T&&qT`i| zwIqbNE&;+12|{y!eR!g$1%~J6*e&pqYDOW--7N{)1uAl%h(#Au(-KOsXna1RRaD>HhX|(lu-*bsT}>^@oTxlWk-0otsVQxpqJ!Ex zzYXh54U1&M`G+NtbYKp{`>qM4c@9dDJ@d>(k}RP_;waD3#OA?-;79)hBx4)@)yHzA z(Vwcuss$KSax>1`Xoki23lSo3jMhec_EmK-{cQ8u;$Yi3eM@k|h|j()2rc#|q%B7h zsP0mdU{MH{+esz)4obUenmlwf`Ury2(sJaAF|iTJ-D+$7$;^oAKBMt!kHwNSbIS6` zDlReIrzEQ?nrHkWBk6yuq-uWmB-LAPhbYE3?L5np3PEMM!D#T9y0e(62`Z>#Df$YB z4b0C0#sD;IR>Bvp?KvWCwR$j9aIQ!*akT^mjReM5)q(B*QH#sv<)sF=IM|lVumpr7 z7WcLyi~Dh+3siRPzQD^U&hhzA&2(4}Yt}4=x^W;ccFs&WBjVWpZ{YJY7#29c zSC&w8>Tpi0Lx9bpgFb>sG|CByp4*wcGJUBA%)!)x0C$zQDBq6!9saVsa+?TGi-*3v zGP0)SI4--NQG4;+Si1qo2)_cpP* zhTcovKRi=Wc?xwj4gvtS+-P_(TPOOF`Sxx3Wkpi{!h1o*Kcg{_(|?|5MeXv(Pu`T> zYJMlF;1=(%?;W#vKO9UMRbx4W^qG%8o5%6Ydu)XQIVOLw-L!ru6KM|KAY{S@+uspUYZy3Yv0<#wW}%oQORrOm}1 z?zP3ah0jq%{D(pQS4~6nWCp3a-}OO80Bw*T6O5J{I2vTNw72jeQ7E~b*g#XYg}n#uYtcelBOKYyMvR~s0BBQovpznu_*-Tp z(`wa5>(tlY2r9;IQP*^DnGm-2ro_`43>Xt(TcBRd_hp=B`L0oFqJ3%YCr7D?Rw=A= zXv}KO*533&Yi~C68VuETUws+JRwX?Qt-r`}Ta+I*9i_A;6+u(=!Bi?D4$C9uKE?Uy zGc?sy2?R8bz*|mp79P_W~4(Z*NlWO_cxkpZlq@)Xsb*P zl7OHwXprG)eNe{x+?jv1N4AKat1SI)POb~*(d#sR8<#1)Fs`|ux)p~RnpjY94ui`V z>(ESAt;);?&qaQ?KC1zF{LYPqZyB^19{!!1?L9M?`zmF-b%5QzePfRo9;?wY<_KMz zg*OV(vEh^N;k~M;n=#>gcy?62jmd$g`8xY>8vaEUYf+;9j+p!!y`xJkvU!ffXD=G% zHAC=^S!5<5DvL}En!jpWej|WAeJ28a6Rj}WeiT0YpD?W6|F5zahfh4S{R??iHU^4= z-VgD&!J8j%9&FnF=LE-nERVMPU*vXk@_}s7&cqo>c8gtkc3(ysyOPq{md5?9*+ZC9YcL)lPguj^n3WMKP39(dUv{v+kGu76xWFf{td=%_rbCE5OGx!s)HL!Uf4 z#3KfNI2*1Az`QTh1|a{Zf`w&+{D*F?Q>7| z4h-~phqbc82XqkVBi!!>Zozxd5eJ>cPKIo-D_55seM3ht+dvD@zqRf~_6^o*z8qZ# zYE8b)P@zT-1SB*{YfSS%8;w!L01yZPpf9At>4{9}n#rEZq(Nq~Ck^8>*%P7Fne1^} zlvBQCNv5Vy1Be;tv?Yy3BZZOLWU`cBJDOg?x6TJGT(A;2mb0p~ zczw=CPo>ny>$4?5_4Bd%^rH099MYGI(YBP)buSa;vHchz>}#*gL&9(jYh9;So60bu zaaxP^zTsM%Tjou3+E|ehz7@%Czt=;pq8a}$k_aWviG9e1_W%e)|Zw8|}8(wkj4bRLu)Pzm`$zh4RO((A0|1E>r&blp)$^h7HDJLwG0; z?bqdz+J69gC`i@0KlcCt97Pk)SN;3*65QKDm-h@a)qB1_7kI#h_je?l;&8oHWeR=s z#A&Yvh?+7$_A}7PCbtDP*-sP5mlPIo*)j>0Lf)6yTAH`TlAh)VK2<|VpWHq#bbj)6 zAlRIIgEfhp?Q>s7JiSa4ca){ zOvegk%*qKi$VS|MGaYoqDH_iSR{SMat!2q2+xI(BcA18$UMj34?0RkJr?N_$;!mWa zU84kKefbR(;$zK4bI>WegJv-`0Lv1QQ}&ME9n!+i0O#P^5@k_*K`TkL6t3f9%r=8L&Lgo=I_#lgZLa9> zOWMxN^|(5g0!RjD@?Tdo*O8_@N5AwmuLB+RXKpgK<@&P~^yfLIJM*d4-7<$FR!e_M zfS+S}GnW|bx!ybmOoB!b{8@nHm_cH@(?jEx-c$$Z&3vlQc@An7PKF=$4OWY8rdDds z*iKwE`DvPTygm}BJdb+Q+Q>&013;p(-binPH{&i=yG^8^*p0ia)u=af*PBhvDU;UF z-q1$EcpIg5S($$1li^aGO{vb5^tT4dh2>+v^XVUNF`lNYPHTWBNXWG9r3&G<=4k@$ zsU})uP0*W!Xe(&X1{`P-9H)jeC%}y1Yry*M;2hjSutwwihN}(5B4@g&(x{@Z!4`6{y5S6SUAIe8ssaMxZK&8IUF9t!| zosa!p4BQBJg~_gsx<=~NH4O4T!~pNGt9YJ}44#;<7Q z6DVkr;ZY|)JlOKDVZDq3X0sY)ly{*SSh{(1yeWqLJP4c&5C81l0Sr!ezWV1C&)HRc z&#ryFRU%qfj=lbtInsVcup!5vuPgS)^8^c$vZngbhfIJX*J1)4ETgd|m4Xl)7iD)?8iqhS^yjm7(W_5iPocCdGb=hW65fKvOl^>Ca#*RU_%^WuxAm z)bFRV?$+#Km|d>R5nU&@W)JE5!mZhZy5f$RYr|eV6bWG$q5!6%@X}6~x-r#7wiWi- zIvriN!25y?jjPdy3!Ivp=RH;GT{5XsY-~SX4*E=9+PJJ_M|{Gr@}!*Xe|b! z7W0{rd|pW z5xXlOe+G4$WL=Y?lff%l*OaWYvXHgP>0q?z$Bi^f;9SK#X?v0B zk{7uy=}YjnT<|G68T-BpgAU|eX}vNjj-IGV`mRY7x{Vcn&?~%36-jY6+C4b)A8|5lFB84x(>2%HQWgk$YOn64>CZd;hHSz4IR z-kBz8D(`l}5z3;q01*(S1F>TapTo(K8c{E1n?vH(v;(mZeT;GKp>jggvAvgwHq`KT zS_Fm7s6(3OERSjhP$UZ`q7KPjXTU}#;9w&oP1wj9g=yqt6cV##HkdY6nk;j?gv7#g zov@6Fo(PV{bW|ao@C9R2A=9oxtO20ydlMF+o1CYKpg|_bn!pZ`2C);tWYG+!8LMd! zj)@UkrZp|HlNgjCuIs@DLGAxox9IHSQ{d7m%$MAOX3!~T8H*9F8%}D(@E-=Nuh9m* zfZ((!ok^V+i-SRzp-t%Gl(bPjKjx%f&-4js-WsIT*`dCSf@15|>}d)VE4LCd<$Cs3 zR1Mb`Z$({kMaw*)E86ApOl-Qww2H~@HIn;TO?E?cja`H|7AeDg_EtI~%_wn_sI*HC zZcKC!i!*|&G*mBAF;yTBSdInlLX;bdGVOBAv*Qc%u2cpI>Po_NgWgI?TC5b_?+W1Mj@Fj3UwV48+;Fd?GFz*Hb+CVMO&*jyja z<)zJJkLH83An`GP0yw9FwHi2#dl7Kx5H;}xW`BxNuJEYAX7mJXD+6q23o=p+qI7tH zOPejo22RBh7dEJDVvj+%-#5Q$kLr09Cz~{LTL@Yu^0jVODX5HkI zIpdRA0%#vB*g}k~6V)|3BH&`4L8|YC9s?&-NXeJa|HdGOs8HGiCxT;b^`GmZ8 z+Lv`>*kxps96|-Yd{8J0V&*yV8^i*Sb6@5Y3c0r>Q+w)*rv7xAkqN#;Of3wmIja$e zV3D;Vzl3B+zOEq3(EMSM8;SZ10LMyUm#NNVSp7GjYP0adR1<%X{!yeM4lJiPZ82a* z1{}|RO2AJ!@Bw9$iiwN3-Haf*EV)5GMP*+O6hGLU6q+@Cni=snuw6BffH@N!&|%I5 zEGH*Id~QxeZM6hA@N!hki=#8@5bZU@#NdC|@oQV)tsoAg8AzgRbbgW+EJuv1%%q*C(9#*Q5H}~&BN>EfBx;Wlt%zG~wl2{I zjhPHUY+4wP!E;#CLrhMxh=W}TGpQ~GXRpo}_c9GVi6OcuSm1Gj6#v3hfg1ZS6hrR; zYmAZ@R1__TjdpF;=0HYp)#-?7mr>_p(~vu`rALXC-bk#d7}I4?3IQf3D*y{k<&*=( z>XiiIyg-FXHj&W=sGMF8DbN6R07|sNQJYQF4 z?0ISfQ)NI5xp@B8%;0)nfQvk^cL*-@o545p(&U}`JyZ7IaAEQj_6ZEf@1}rn%tJNX zl^iWLZO!gdairBDUC#^6(~S-LdqT6%DU;$%mc$t`StwlJ5t!(Jn5PB7w&4e@S5L)h$-8n4D0&xbOH8T=c*RJ( zOFb4NUy3#*mic0u(O}yh+!IgEaS2;!eW_qdvNNgz6d!$osB^) z_h0fNpvI6&BPmwt;d;jT zT>Ym>SXHc_jgsoz=Wg-66kBhTuwhrRQIjCRHtNu`)r04P&Gkih@V$V&0UK{4Ouowf z6(xoczeKp(@-k+CZjbV`22n6TF%eKOA;p5laT+N$Xr|}s!QyS3a@6j&o#|jZG*A&h zSlLQkoXkl%!rB+b2(V%V7z`HyTkGIpIX{f&LUcyC9?0wNIKCR-s}0e%A=yZpx5Y#Db zmJQ72J|67OM>E%Z$3pVcXUw25zRZ*sH{wmD%fLxl$znc#_3qF3Ig=eB!AVH21d(kL zMBBmRDFQ(Il0&9XAq?Xtld(qkQmET@?!V>DgYCt(du5w%FWMj4`JMF5w>znVB0*7X z_pBm|>eJJ2s@zQuhB&kh~(g9dY1_)6j9`MDTsxgAbl*j;DOR!$PI z5*$Qjfn+{1u!SeK4M#f$;#r40gEG?oNBEXNJkrk&YMOmKJbiD7gW-|9w*;; zuoev#t4+8)B;93{&k{T%m!<_fI@UcY5l)E*!C}HU{#liV(W728k-aR0-H8&ebh<5BhEGoX0!kSSQ8SgP@k5UZ5`Wew5G6c$0MsKx^@O8sPA%VvRU`7Y7aeneVRr+4b%)@1!$<9SEbD1GH#fy!y3TVK5 zk6e;a$6z7Pyw3^m(`H=efL69`Qjjg=n7uUNWMd>TQ3*Z>wKd`30fklYuv`GQ$~JA8 zDGLcU;5(3|X{ad_33TQon0nWsXM+59!thwefs~`&EPF8!g(Y!l`8X?`G!!99kX%U6 zccepv(;Jyk&USD`P;`xR3keZlde$0Eq?aFbdU+L?l>jH#OZKOei*6R77HB_Ei&kBn zTs9|{tHIH#i(wP8dAWT`ftyQXPmmD=Z@UD@o5q#W2jP@LJpsK02?5^Za8xM}o*dn_ zb^FHD>0{<(DjZ;KC#tm!9HYlHMCG`O?tYi7B+h$JW- z5%~h2m=KhngL@e$tV=`|u`dRu!CVS#(d#iaT2oz+8LnB78CK2J)0ABi_+(tJliv)B zZOX25W(qbIOh(pp+-1R%c+~TwxLjDNtRBQ32ri8Gph%z?cwjw=wQb3zLoq`oKV}JNmYkRre%q80$)SWsQO#>p z3}qFi?;cgACL4#uVikyNbE9K4H=08F9&?#)fMk)<8S0Q}cqofI0~eo$XJrBk39k}a zCg@Y0#Ldzoo5NuBwE43XwA^=uN?1KU?GvNT&D(ydMr?T8fe@&$XP!^?^PhqeMkh(ugT z7cv}<%gWfY*PJoW;uA?0rmf+a&BdVRtbDTOzB4$rb+_?nk-(oTz!VP@VzeRFFEQXwzGglHEE{?#y@q^fE zOdK`fhl>6`n^s@Lf>1;kur;v|KA?=!Fk69ia!{G_ukrE?7^ym{qVWpd5jfC~&;IhC zp7ZiDBk7#l3c_nebNV_hJ!Ep1SlR_B^Ph2OMJ}0KTl=^mbHp!Bs`&Sk@`~AUNo<16 zlm&Rn1W}$sjRGhsZ{q`sZ`7s?JHs9^V=V0qp1D-KElo-C(g2JeN6xzF(x z_l8>*crwwPSE>8^;Y1E9#QmU(h-y!-YWm_1Jt;~OT2z>z`*iw@zhxkO0j3uHmI2bX z+5giNLN{qU`aXaJCg_{dRACj#!? zo^80bDJHp}uLwe07|U`Q*fjx{2J~|EE^LG7QL~?M%itZ7Ml&%cdjNtLKtEoDNn1qtd}4!z1Z1 z?pOWDxJ6^>gAW=o=GH1#8zij&It2yG1G%|4TBSYYw}cQC3MA78*XIntYwjDa$I@aC z3^@# zb2uQh2ObRl-N6bUcKt70zhd8Th55})K1&d6s>$^M3Wc=A0~5lT5ncHW;h{4t-C5f} z;qJj{6nfHcCj#P8g;{wQla$RQf0S)a5*W%N;M^-8Dj>XFSW#i_M3i_N#qU3MzNAn;}1@*Wn} zZKEt0lDGs$-zaNqk!U1#9l<-s-jMS1RsWDpre%XT(5%i!pashzwhkSnp#aN7Z>1t} z6TZjtARC~2Kh)fdT^%-G^+1&RavM4MZFIsh&Bhq)Ks5>Q=L)5ZpQ_rcY%baMWuD(9j^X;T|%{6>EjKdvcbZxgO3HQnN*1+ZUtz zLzcp;J@!7+jG7G`IJybqQtOzXl&sWV`X2c9&9WWa)A7f@!M+fal^tQLV-oF=w|w%e zU;o?#j|ExT8JCruBcQhP#QcU{t!>1Bq+PGpa*&k0+3nUPWk+I*QCVG=lpPbVE-9H+ zGJ#tzEy1uYWm*<@&*uSYTM>B8dI0l;t@jaQ)MU<*n8jIPr@oYRzz(v>G__sYi1x^z2$bfZ_q9}xkI_#%$N$R&;tql|{>6F(Om z8h09tD4MAnPU*|HPCB5{j7tM*o&gp`87AaB&zN`6EtS_nHzlzc=uHRbtZE~8M4nTE zPCc78iVaEGa0{?3m~d9_k~{GES}Yc0%QK*-sYlT~u|&NSpP+s}fZ z19z&biGio+C=S}D##kU`hc7l2(CRqNY!=ddn5HKeN4yG?0%Pn@OM#JxsKv`DL07qC zj@e3K(`l1KJ0xovY4UXpf@5M5SKdjoHTfbx>@bD35QY(7AV!%Dt{qtCk&#A*S(M=z zqw3pngP9VNp~M#VPTmdQRA?X9c#693(k^NqvY{E}A|ax?i2oHhEadHfuk)gQfs&rHl=h#AR^_qsc==A}B~R zdHnszYf zH}-^~hw8!Lk$V^o9(cnH9o$1RbZ`&NO@x%$pXxLzO{>i~_;@7Tm#lZNVY7VK0raz$ z0@$d;Oha{g-7D>z?44P!0Yy>4j+jWpr{qehbjGws({C1r4xMKmvSwk_Y>G0|tZ1`0 z?X1=bHE@i17*l=QwBe`zSbPiMHvr9Q=7%w?c1uAjEWm8GM|Db&`NA8-Xhh5p$TILW zM`qd-2Y->SbzSU7Bn09%WJU|X&uI~)tE#;|QvTz6eP;PL!2)pq##D|DWtdkdp#;oC zPyi$h<~-LcUS)njjdFJEtq7-dYGguf6N_byn`LZ@)G~*2GwX31>y&yhTKKz&0njr1I!S z*oih&Bied#Raw-2%@f=I&x$(`n4^2oJ%A?o&oNf6b$z>pw zGpRfTQ(6oJhumbUmbd41_yWI}B?AdCgS9Zu-K^?J6devhoOnu-!fT}3EGhDID#{dO z8bqEp{zs8_S4v-`wFpye`|rEYN3_AV{addG)vI`zBxl%y9|MU$!ZP{DiZ{goBqlay zrwfb(VFSOK30B@oNE@(s?)Pb>x$i!o*6Rg};9$GI!EwOgkQ$Gj3^DpjouyV~53nWL zTJ|DjGRSFjU8Y6$*yL?hTx@?pX&!}NL))tJQN;j|D5pP)iV7?)McSNIg5!F@a(M6ug7_01}q^1;jem(r(cipn9H%G4D{Ko&Vn)1 zLyX|h%|MN^8Ox+6ENDX1x*-R2 z7ldGzv88D)E>!UXtXqVu!E`X^>wAEKfW`kJ$1R)|glwrKtX@c*Sr9n_9jye**hdsd zv!e@qfWj(DFWQr}tUp$>5yV|Z=2}3&&bf(NohXC}fZiqH%ScTan_0{6t}s*dwP#22 zSRHx@HwbAW;jpoKk1gRzSW6-|wMf9!0;1j`!9gUEZ8^{Y!iRkCX;V`N+(uz33>!n1=yzd0q-5P#SV zE+f`Vi#B8EHid>NGk%12$O|QefK%nK#J3YbwzL z&aeP*&@lx}$y@O({s*ih<+-1FPlo#^Q^g$ge1`X1IiAlH>)hstIt6Ph?ReS6+BJY)zm{&V(+GnG!XfP8j0&8u2R&fI;L{67zUZ+Nr(F@yMY2(IhM zu?!DeBo`u&r|MU|YHn=3cypqB!!24vZYZY$fmPuFQnhUe-q?qBPTn$X-a9}}?JN#d z2_39-gF(*$LRnb=8AQ{Xcg{Bk`S>iYl9w^3ta{T|e%E*kyE0?RuMZ12)+{x1PY?LL ze!5b5`Qb2i8E_1L%O18@24WuexvMQs&(ybN*Fwx9PG7Ikgvlz3=belWF21OKZZR<+ zeT0~jAyR;6I_I1dgC(3{T#Sw|-e_P#_Rw1~9Bt8@1&=K-+zQsPq9<%cIdGCuO0=R4 z2GXc4oX`&81T*X`oM5LMHq1B4OFQZ$rg8VpBS5lS0xt2n2uN)=p((D|LuEp%7h77! z;IO705&J9zU`y7<#UJQ6eo?2+gkL^Ql;Uw$~P-^pcRsE$cff%%dEssF5ecz3L9(%7Zq&v zX?7yC0LQfFX#w|6Ewsm4pfhR4cF>Hi!6Xya@{~Sq;$pQT+j}eabdI4E4dIHzLX1E&U-r5?MuW?O!# z-2C1ygKxny64_I3)~RPZKB-&T_}74(u$1cuvsc->K!6A*zxUPLVST;I^ruDSx^CmY zN)up8!aFB;R|k-T(HV_G!xtAF@=l3&$j-53_=vKw;Bm2sKAbGKhbhn+0`|i~V-HQM zX0K{C%wlYoemnK1(GX;$K-EJLkJa)%&B-7yOE0eroG>)^D(*s9U$hC`$t2}-5#t5B zCTuh@DSWy3MIn$Jru@T>+P3mtS-CyB_+sPw4F*}=$03uqcpA|g$~ z7=@EeBRLI)OD+U^Sztgw5e)C!z;K8RjH)%0J}W@Pin4h#{py?cgJw?To#jfmS(;qj zq(&n!a1=w>gIcEi9H<9^)=oa@?ZODR6Ha=nZXAb%x=04Nv8A7Jg3gkh2OF3B zw!q6^ZGOGd1<|DhdM4;$3KZCJ1>m}cEJGKBJ>a!`>zQnar6p-jr5J)K9#Zn5XJOuE z^+um#W#nu0?lbsib?~5XJ1>ccj_}a2bVx)KMxY@nH$A|Di4bKoBR2_XcIs1&J4kRN@74*n!pY`#*&Q zFATu`iv+4AyoKG9?3oOED^Xs^fP}Z03k3aihjC?;W|prkIawl=t*h-=8aR<2QbB)n zDqH6!?C~U~+JchQ1d(WC^iR{YW5l4?6Vccm+svhORBh%W5qw#jxsVgVJ}cDXXHzlR zMs-$*@Wft79t$Y$$3fscSY`ex?hjc*lG@2-j47jml?T}jr$Ov;b^eG=VannBB-gcN zXVA;5@i-X_SGo1DN*n9g=yjR}@GR!krg3R!#A68Sk1ga`ms-dh84BUFy49f~12giP z>c7TNCusyX4cAG2o}cUz=$F{0FQm=+$@e?Fn-fwnIk1+>=O-_B*yA&l93S3>^SE3p zj@q1D%-9vO>&x; z_Wu3F%gY?`Ms2AIjw({FZCh&`e9mPJcm1)fTaIV7tXuMRXqGJ=%DQbU>$a(jW!)0y z6c=#PQpmccRapo?P-Wesd2uXR=R6Ewc-C#(%xX>01S_ z#m`SjH`ttPGXgY{;bfN0$%_J!lFX|!P!OVMu}#^T}Mp2bHSLWz|5_ z!a+xUU_cV(0!1q|zs8@bPEE128amZk(TclwZYDjEVx}xWx}PCUH#@3bjvDC5PnP^O zO>Xj628WE2MGMkVYWCN^Y<7@Yw=YC5;JdrQ>Sqkm{b!sz7!^8RjI4G%h4ZU?g^}lpu z#cdW4PKuOCu}xw9+Ym?3-qwou<-Ye{F@`4L9OR1j{x`L+p`+<$%~?!W9Rkp-4gqME zPlQ7NFoq>8NwAc8qi=}r*sFM)?sN!%>QiD1aTFB7ehvYc;R)WwP#@#uvx5&DJd*S| z+(X~c#6I{)rb#H8oAMc#Kck)gO-xH>LafIGHOmXa*#xryWDwLZAD#!ma{&t`=If?n zZvW)z3_v=#+qnZy>iX#g2Kc2Tz%`Tz_>R5v01mYX@EvmjKN|OD3U0H^h(CUck(Zov zp|9V~I_uzL+8r{Ro{a+XB^;x;N z7v0JzvK-{``ty^XiA0Gw8aLI;bqcX>M)Z2(pH-C8R688zlAh49eG$+MTT5Ef{uTx- zy~rJYg&4x&IzpV^ODoJI;QYK^1?{GyseKS2QjYxn*Q2@Ao$Qcc`u0-a9_;9iR6Sf75qpJ39W&7`FHxjK8&ETF{JPgFF)SSPLU> z9v~;=nJDNnfof;|bj~Dq%%6oc)xZ=djfDef* z9<#RH|9Vsju#fNnv>j_#yNEtbmnG!2IeEl8ZCZ*uIe8*Y?F_d7MKrY?BIIox1?spi z`iX#|qX9*duHH!%(G8o0np!Zm*1d>Ok6Yn!z9Y3JKT4CJ78D$D`lP%ywt~{M(HvC_ z0Ev9!W}(A6IuV@0f#wZDnigsjf2&ooz3Ei`XmM1Cf)v_HQRfQ?3hs8w-+KEI-xU;s zyDO0OWmXdIDSuC|+QfY~upx(7OlX2ero0hWtP;d}W1dD*Z=^BSh~lY`RyYB(=-@3> zXIOWI9oxZUXIQUw{B;pT>xK$R&*993OUw?Xu0JJJ=}d)psBu z8I=sf8ZRlLLJfIX3Ir+^2fgW$O#5Qvw)_alm3jM+t_ZRRbtM||09Wm*zh5aju!f71 zhmdjBgs*E+6sPzghZ;Q45esJJVg)Q)-KRR{sv#)C3Cme|`=r`-h$ULpHUeo|_B4K$ zeAN>ZCLYQYIEGNS60= z9WN19NnsZsHK>hH9;|WcN7~}A&B=p-M;rcm1e8OwmJ23lK_{<`X>ij3V*I&YYGCO5 zts@td4WVnT` zILB|WF58hu897pkQFI0QsDM>oSVmJ7v?_)yM&1i24DMwojyf9XfhB|ZV%OmSjUc%@ zKyuh1ks)DSco=KEsnu0e$~r6$)mnKUsD@i(Oz3XIn9g@&Jz{Fx$g;Ov~E<#nsaRA5y*^`2=Dog=9Kc z{4Y|EnQQEdGIVN3luXOf-qe+az8J~^mhVsH+nDk&NBdL#J;A|ncFumFiE!K&sBeFT zSnsUinnJmFLG5@exW2wm)r$FI;z~Kdq)xR)&3=;wL&x+9rRf5$m5=Jj5}54?SWrST z4FurCJn>*3R1kqZQ$druB5q9;Awfezva29VNX`hKPL}Mc(h~Mxz6<4|MMWv6gp}l< zb{gfA@y!NHROZ7U8C!CwmaJz!CTlhIM5=1CR;NoRmc1Omlu%_aGlEg}aJOnWqp|7H!*HY2U2QOreCKoMQykmFh8ZAuZB{c|a}8)7$bB63)*f&u0=1 zA^KrPz@>z17&0xCh-Ld$jy5Fa2{lf)J0!Yo(sbn4ltM_}oAz=jgK1gU`q~b<%asF8 z=%Jtxu%?*1=i5}7La_W~^@%w(F}AXIXhI;1+Xwe5fm<$vR}Z_ACbYa^V=bSo5!T;8 zSYqHOE3zUY}oGI=;^j-&gM!Sf{dA;=+ef8Yy*U;=B{R-+EtrxwFpYILN6`zQt52|Rc5WO95zVEc+(XZ>5#4*$Vd@_ zeP!(iF^rdOWq<9JHR}Xq=V;$>ClefLBL!W%=fh*Jki*VFn-9 z4C2G9r=jbiE8ko+?Z}dy#T~cT)q|qut{xa^OcXZ_pcFi&x!m8`^J3X5oAMLw!2nfh zJ7ld6`VJk_yO%WwYKI)bN_>UnbTD(f;Kl;muPbwD<_?%V!ESN*3Hgp1n6>nXLXbaZ z(&iZQzBn%1*4;LLwFI+4PgaCd!n>Bh|{JOj0Ont z<3lio$5t>JVFd#=C=@ZU6%69q4K$j<+h+T_^UZQ&SizuG5fb)UwSr;mESTc86$}N% ziJ-twPqzmg+%SVJqMU|xj7#5hXcPmbeKjQ4V7{VvVL}MN2hFmg443jaBo)7k^rcpC zFGW(Eiv)dkr)ES}Zek4Y75!jm1R}Ddw+Wwd{JHEmx!WuPu^cg5+qBTCsE-zgK%Ghl zL)29y)M7YBs#?&tDebzof1)k!*GO$WAQG?9U(t}Z!mJYw1z*MCaE&Sf(GCZt*T}}; z1=Dlk?I;bLy%!3#<5+lGjIcZgwxXx`X8~Ksge_liVSx*MS^M?@-jg!z+aoto-*n_D z1TR*|$|L9jn1xw1U&BH#oaVt(qkL_1RbnphtMaXrioJp5mO5u5HI<`(rEv2wTAtafUCE*!myeXfO^X3%4_{$$o%O8YxJT z!mGGjwl~wfD$ehP3^iFtG*GU*l}y$=Oppmc4?JWh!spjq1HkhZuxa?G&f{UZS@~sC zeDZM8eN@TzcqobibvOj=rRi}5P5B5j6GKj)ZYks>_4bJ72Es984@g7Y<0k>c+O1k5 zFm`_Z?3S7Y0>PM)mXLF_2G}QL z&fOa9QLIvdcr<`G+Pk7}#e_*PYgt)TbFJkzJf(9c!;p?xH*PIIEYIXY9%u?$!%m3A zeFTDaTlqot$$@U%_QF)|#FCuqa z;(p+W5d2zTnftx}=zd_L%nr_YDA4V?p%PPDh{I}TtDXB47E;$ZlwbySHZsc8j->Ft>U0eO2@bQGuw zv6^O#aeOHYv6`NYW{viF{yCQfR|52>R?jlm(-D&QLIV6TY`(g@Y*9MKQO8+d(P)B8rdh@(3O%1K^sCEs8E-DNT{bn=tL$7p%ZA&f*DNz^EJ1`g|HkI zMN-IyzsSvc&-arDP0!uhc-RsK zxSI6xaE)Q_4szhI*j2VGMG>Q>DQU!bzS3_dO9e5JWIs#Zr^uC>;(yYN33O$S11N;d zp(N5#So{E!QJV!rSH>WpstMW**MqiA@w7uQZIfcP1EjZw0P%c61Q$2jv>9)u%{0f- zWa zXNM+ConaYBof#N1HRtLyb}mY%IiPHokbPD1H8GiL3+guXPOuSd4Mkte>S<}kt@!`Y z)yKrL5&B5Ir5N;XqzN!%ih0 z4Nc!c3r%Bu&3TO`XEWv8)vvJT#p;(46Z@f<0LV)AfT>tp1r5`RGR=i1)^LGB`&?LQO8$7^sb} zbbpf!Q+$lPJVs8^ME?gOknj~bkH`2FCE|_Q%-PYU9SN}@;%f9>fyTW2Y9^P2f?os` zG^wL-Ki_z1`WOkhR+}aGnd~^RxDR* z&TPeU^};KbW=pN`wMuv+FOO%=X)-MY$CpBOyzY-@W+y40B`3Q^70WL2}#+|zDC1~PqSYuVps(q5deGz8Uv7HrKobaDQz>D z%qta6@fhE9%Wb8{H&=%ErnwPeIgL}GwIR$>mSvsVJG0uF(y8`UncP0N5&`;z$^*zz z#{}~jJE<%-b!6XyB}(NRB&>+XG|dvs%Oi|5Hu+H-qZ&P8qtgO%u++@1Y?{4o6$3yb zy%n<3K-S|5$vJtj@7&0RND|+?gi#_*N*LJZV0B{k%CaZ#uv32c4vdms*kf#;nbhlE z*%SG$ob?*1DXU5!ij7WcBDfXli!p-=lK-lEq`xiB3w7~id7vx}Iwnftc(W!w`%IY;989uKZ<5Yx9?_Vahp#nBv$yL^a_ot9wjsHSEcwY7PQ~qS1Olak#1A zqShq%w<&plb6ft1-IpJ1`u51r@pE%>PjjF>B1~ida?x2{-o=a>_`$?d{rniGyc)=c z8fD?SFj?VSBn%mGc`a8LymzEX4yXyJU|V(%1S<)A*wVcn;uRQq2C&&;BM9zmMkCK4 zILxuvcbdDfaLf}((w^MLuwtzf_T+7~C;JWg@2)+0t35g7Ph2!_O1{K4KuxFd7E_Nn zRQxb6@3a=b!dY7MVRUkrJ^8EJ6CFmFmw#7#@$>;K|$;a(}Q}XA0xtBfLx%Tht-N$(+GC%|DR}qCC#d=K139h2BBl))E zHdVRbgz*h%YQ`yl_xmma_;Ok`&uHJbEDMgD+?>FCVN)$BzVo`=Fq~GUL;l4I6alTALSJMI>9sMYBaSgf>)h$4yN+-}JvnVg`3v&|{ z@&{@P`MwOSXeHs46>>D^7?kzn3Yi_`qU=LFVqk}};iO_FjP-pGM_nNw5&$S{y%#;S$SjSrN5e6)(~D zpC!xGiBvGUdho>Up;^Hb52Lo&9Kpn!E{V{ct(bzjPoTpo~N~I0NXD|b!%xC)Cs{R-xksK;sn>VlXWdGqsK6}xRwXfx|W}; zYk5e;v*31;9WsaG0f}@!%3WSXQrcQhM|Ji&0XuHm{zVqyT&bhzu z)sZYGvK`=@i#uG|k?l@hJBc&JTdVoC(oT~sw>2$)m}xpSa{fq67j@To@HLpAB&Nu1 zm?~gEE-q0Thbq(*nW*gzxC@229i{aY1sI}Gwp{ecpHPea=1iO0s3g zbYU&ubI$(p{&?Q!eSSaB%jfw*9B6wng`(8c#1uC1_F@X*mhH`$$+)C^;RZ*YXVG`p zX3=-kW^9SR(Ai8mrfx=&UC15+5|nUEK(d>?J*c3cFMdcDD~-!Ay{!2vJV^?Tq(ZlK7Bxvc%^xZj$*X z&Vy@=FFonAS>~H8>@D=lwho4rEhV2%TmE!Fp_cikxXZ%Dg+vL{KrGBMpDY6vb${w6 zKj-;rUZ-k0QpBLXl}eegrbdyB|>F6cdDrd$2I>^5Cp#7E-&ljUsa69*8e@oxNAbUW;> zmL$k4P6AnOHO;(b+Fouo+^LT}!0)IHgAG#qR5GH!%M>ot0rnhZM5>Tc_FMx7)ZuHm z1VPaUAN10}2UwN@ayu?sR)h*?!%rhC4p&v>+jKHdwIwMoN&7-TALWy7WsAx4Z#^e< zIhmPS5~;=fEKw3sat!(-3DS}!#A-~kRGBf|AD1kt#xl(eg~Lt9B4*Zb22+6R3-Nw! z55i#72#I5+pcf`2j+ufkBqS%rg1-)Wb;PDf^NVc+Tv^%>Y^_L+TOa?(h^ipXEAho}Lwe|ktPAI!Y<9Zy(zB{Htt=LXO2s)=o)?N8P=Ho$N}n%~Py!suL0h*!&AA zboJ}Q0{Zo`s4KeM7SN)aNBAaRLVV4a!ULHvIsJo97+oIMV+k>j1VC8qFn%HkqnB2# z?22d@lMW2K)xaaEfkSFQ@|{K!FJtu6WZ4hS{Ybsb(mB&uI=^0kLh5CE*yWg=a2CK$ z_m)-9B-#4pAR`oY@E2qI>t}EH^@G0{_^GTq2B(dTAnAzc`h(3za@ue=Cft@NQT>qQ z-&qcA;jQon(rXsyUd8B_Nx@uh42_RTi0)53pT)Y@02p>Mfl<6fgL0cL4zE<4O#B<} zT%B#&O43fNZ;2C0MEr)Ptqc$FZACgL8K8TJrfZom>%wgHEF^5EpN z$q~6Is%qI%?B-%fu#}~XdT_YF23S!2k=IZ{pOPyC6Yx8iTv-4&jHC-Hxw0^Pjp~oQ z#zg`sFa|WaDc$Iggsqb$xI6;nAKNM<7{1Yx&mL&_2 zDimy&tcvevTjxg-xjvleJ@k5O36kA3&Dbf=!|?0bx=>45&5r7mE!_$afbwl`4@GU* zA+Lw4%0=PSeaDobPcoA3e?y|#<^K)z^OSv0blA#o(l zA=%?M_{Ij$krlt7!h4x$Z~hFHwmQ2qlj<^vI0RF3#H{IPHlkjfYHFcV>};m(W@&|U zOttLNttB-vdy0b3^E;`xiKf?@v?9=U*ocuHNGxOQfjo)VWlr$sWq8lU&_~IiQi-=$ z=OrzZ`yoiDQ6zTSj6%^m@QoQK z40DRP)Z!KgOR!mR3&-|TM$>P(ykA>5YMoP5BNJg0fO!d4ByYau+XTf)pBh_Wci1%o zDN(=_45(hefFF!H7#2?uxj1aZA{VlOf&^DBD-d@m>kp;%$-$E>r(8n1`k9Dhi;xZ8-I z;K3h8j(l}4@HTF|m!rR}Et-EfTl7U~v@@5Y(K5_Xrif*;(q?TDNzvM^4ZTRmuM*R5 z@W*?gUU+$j7MP6#u%xeS3XGaixn~A1M4j!7c8W&QEuJF8PY*DwvsY?SxdhIv=o5Qq z_J!|hRB`RquhH0@R2pNq$cml70|vO9LDN+cC~rZwkhkB1i3_f48zO+U<9_PEniTMp z0%{}1Mwll9Y!ggp*ASR)*25=2#6xt=o9rEO#5d?BmANXuLq|2#b!f?2ys(H!9wG&i zEFyA9A|>Z6KVGSDqai(hM>wHEHGh@T&Xj_fuDT*Emh|E~Or!2)>xv_KVA{F}n&auB zDhHiqPw~b}4O2?8io=wUVRD#Kh$;?Kl1Q?3m=dAV-lTN_rKlf?KI+Ewx4q^p|-1rX4gfdL8AB8O8d9Bb@sc}^$SqhlS2J%|X5`3`utx5Ukblyn458}MS>M;uZcuw2?FM1lLRm*cZ1bZ=SvSXMDeHB7 zu&BajWnJm&f2pmkf8F3OwbRvk$;!Ixt@feXthfV}NogJKx}dVoOtP}Rn+056Z3X&n zRy@-?coRcBOetJ-*jtZEZ?WK|m#+^RHr%~qv}*taT;3Vl>W3cfR@ zN~2=idz4jajT*?N*xPb7#g%I>A}jAyR3S!fb@8Ob#A2} z={_PAjeH%<;Bu(IPE@!EZ%ooYrLS(KTcY%BuL4^uj7hXqV95m+;ia((%xK3I+)0nN zRL7S?!8O=kxPr@(wkh1&quq5O1($lOwS4im5U}6s9dxPc?aIZex4R@QWrW+T-cnlJ zs*2StR27)A)mzkD2`PWAiYu(5(Oh3?3L;sb z#`V{Y>xZvz^uyPg?z{;75KKt=;Z5o!)We&t9p{tIF#;nnKPGAv% zf&x3ER8;gr;f$>+Ae+J&TNOayAUS$)*n}RA0waf>d|M|Ztgh|CP31bK$1-vbNRE!Y zN;A`pbP9;o#7hcfv{s0g=uO3L&pOuDfs7GrSoCu!<2HeeiKmVSGA8|OdLZMR0~w2M z4rNpz<6OqE0~2uv=;LTPF&h5kWnTcIK+&e-!_mj#b#Vo#>;phBZsF5 zg;f_T09VQd3$q(Ux)wYVQJ(cW$pHOC(MzY0K-Imk>31ThFts z`{`|mn=^uT0u30U@J1`HB+giIMWMCgijR1z;z~*SF~t?d*NQ7XvuTR!tSa|xE3<|4 za1laX*MveWhjjfOwZjxBuhN$w|-m23Q1>Z702M z@_cWVjLfoR&v%`SjISiC_Vd9bk$x_e; zlehSb_Rg%lP|p&ZTXfM9HcVyAx3tSDfE6}#jFxs_;hSP4SuEKZOBm;bMF=I~0-`J& z)VkmZN%{JRJH{gW-@md_LK_c9LtV zDtw}K?G)Eke)Z|rwbNYVWccct*0nQSQ<>CfUG!e7PFd6&J0GE7lFCM@66534xjjau zB$u?JP8Iq3WFzZ0b*pCdc_f`cK%t<;DhfSgI{-sGFTF8wq==e!#agC3ex!)riSmq7 zs!yF+h(`Y#Czb3RQn6D9i15OPspq(oYpYd{@@t{~^*Fzl>t9dsYe)U-Nq+6Bf1Tjh zQd8jVMgVYIq4MjhL8fYL4-4?$!&5tR&x-VOeP?{5u1d>BakW}@)j^)t>aOdPYLMqS zCgnl3u->ZD^dME51d4T4XJP}mgi=cHcR{eh9aPThBWataSw}N~j2I6tfDBFfO6o^d z4|8eOS-Mn@s;(t+v`GpcRIkWtt)9C=zF zk;KFna>2|&bp?x%0OLwll)vokq)ZjCPzftQqY_p?L?x^Mm`YdyKb5d@T`Xv2p0Z;| z{SYV02zY9Xs#y7O85kTDr*x1^F51*SW`^otty-J}AV{L6X(Elx7J>Kgk!NYug74=Q zh73hY%Ep#uv2bzcvRL0Hv>h*t)yKx^9lqLU9VrK=3Y(kCViClGOqiB2s+WFSeIksK zaCo=g8L7N!)ai@f6!h$4d16y-c_NIrYu=u*U1PtIXSO7rZK4s(?yddYegO^=fSLRY zVsJ`NS?DN`vO3oS?pIWmgjt*mz*0!p!O;}Ea$#=~^6h}+A(Ep-B1Zz$SvQVRf=0hg zm^1yI;SwW0+piA*{~|R|vH@2Qo>A}FE+GNgX< zz*!NRQzWfYyP3d8SNa4p_oD77g1%JXkLHHfg#Q!DnTzG8F>n&e@&XG07}6=-Ofiq( zI!)(1M_$Dd-w(xcWe{CYQao}!F5x9|N%65F?Bs@gSgR~#QK&WUcxh+3ekZSHULlTf ze%AFn5wIXFhH_mwbhbHo`^&HkPHt&caaZL~UVV;Hi6&;A26nPg*K4R}Q~__<+bW7< zo*l1QdS<~rV-9ckEWFU#IaegIe0h#-=dRdx?uuw2(+<|x~?>L zl**T`_dy=3CBTDR);Wg4MPE4N3vls#;jk~j#`A?Ez5pA~7moVEP0fX4zVN#Gf{qxZ zdC4}_2J4ym=BLd!Mb$PE0jebyHf$o-C(VFqvhHugSLn6Aa@xyuKUEN&q*5nL}L$YHEpu@a?P-&n|El(M&oN>Km*@}zvanbblcx$>( zB~Er+la(Q-;bcnCxhPIXQEkd(B+#HO@HIHulinK@LC(UWWBvMsw2#5!GA9daf7HN! z06I!~xX9DGYXqw-z9`ygaep})iJ!sQGDkB#rHJg<*)$DDbHLF|IttC@0~(HIDxD50 zl0P*UsDI47cVFj70*AIRL>v69Ia*(VUe~Z)piXW*9=R9On}VFYyD1A-H~A6G)g0|` zLa5Z3N+;05c0cn5bqtM`J-hyl`?`F1^1sS%Mt6mDQ!PAsWWrlw{Y>Ud+vqfKK zcUj!$GWWpT-GeE)BK{mUn(Dcq``m|6XSy)MIr03t>es~xbvBwy2dJ=AhBuQ~iH5r} zxy#zV)M~g4Yx`2G*<@{BYBkze+xx-Y`gE+8q~Gg1ls6F+h)EzZtSstFsdVI00NrJZ zW4dY5eX-b(KM)bjWOKm)PB9)5yOkcarQK94kN&!V;sjIGd3~9g>H!H6Y%oaLaugnj zHhxV2%Z0nmn8nf)W9C?Ozlao)+hRRN`^$Hl@dwp7+wAQsD9gFll~dmT=bI}^#ySR_ zc0B=oqG>#?PgSbYrwr@*L@ja6aI+GvFoRH3nC?O4VY1!higI0I<$MNDDpWmH3b2B) z%>%TpdIc^>=eg!Z2e_#`_`#;(cs9nd?lR%Z^+Wg+6_TD7w@Fw&((w`u3!e%3#w+20kf>9@qo>*pc zk9L{LnFv>pvh9u_2~0>Qlt>a_FAH0kXoIfW!;C_8l@@GR>?_u#<5Dakj6(9M=|`}7 zRQ~4X)y|%htQDD$($qk~5G$tVuKi!KGBE4oU5mIzJ zn8m_~=pD|Dfk`YfKAnUH7;UQErSBrpEg{p3_DT^l4}v^d$oxPpWFAa1!7EtEBr`=q zW?taMS~2x%;B;R0(GX(`0xD`jAmw@Kl*p#d-8{AngMb&Kg^@}o4`ALja_~??vdLGYCmRNsZK@He?xCC~e@6{6PSLi$m zLKZ)zAe>XZYV0qTSy6bh%nI$0j-(I~9rQaUzFt^>b?ClLGJR=DS%B?}V)&j-G8S%= zym*$;W&!p~j8kJftFd`wWGT58V099L1y~?IMSummSdv;zeo<40H(+q`gvW}H(?%9x zwJdRdO_1-}B!ixA-7uSEE-b+Isu`W-yIFjd-A3{&`+TnYO19Y`)JlGZ(sKBIeZ!(kcfJ)!lHsjObA>O9&1r5j&`Q zvTNIflZ0G5u{I02PLCK9aw(}Ly=9Y-Yf3mK==MXv{EifkA7!euUKEU0~`fWrFKqlk?keeHCOU9`a%W3qVF|2uSdx`o=h$}u; zXe-F&p4p(6SE4qt2(4hMq?hNf(3M&`-b$i2FoSknR*BmBga&DWI|}trk*JA123>`x zX@F^&8i^YF3iTXXGI!b$%@Yvp-Jmjhc)K}JD28Za!VqopK>FSpYC$M;Dcpf4*XyIhUp?HNs{ZPL zSbX*^b2LyppM13e_`haA%&o4-#Xn^Wiaf;DtH&2;hNME#IE|#h58;RawmfqlU1h#pL7*6Q=QEC zYUD(8R}K%*+1L3D*qgB+)RB`Dc&xf6Z0xeD!@nlbMV>6|6bs^YeRg*^q+0ttsi)07 zZ*;4t+T_L(#3;8Dn9)4iY9`13a=1$YIRR(Dxhc8=pzABQ z-@^r9U0)zig7s}(Ag2K&XkA#-1%O_^LRJCj)LanMbrQM)S1>5w#Rn4bxAK9L_)b2M ztrg7z|4=jw9Hoh7k-V+271^a^qKC)nfVjAtBUp%AG4FBQiW!m*h-3269Z!ICwx;ULeoFSCD_Dq4rNP6 zzJAi`ZbG03G=yUwf;G<`N&#zGd#Mm8q~`CES#OGJzZkx$#T4(<_DvzwXVu=P!M1%< z;F(VkVFejp9@xhcbdCl@7)Ge}i;Zte9a*(UdT#XahCXKh5b>XXS3i(nzKwCl9AdF|BhD5Qn5LUQ(Hk`Q7emM ztYgfekh6PY8U z11J%6k%Bi+NmNu&^c&i*uh^a<22p0S^nJx@5Bv6 zs325!XQWI}?qJ(jBKjvVDyyX_4 zP86{v;&JwoV;QSweM}ZVfWM3rQ^G6k_kv(|{$MuPBu~i~qw}SH%z>tkv@os>zFE3< zpb-W)hq5Z1>@Y01tUdxVeIa$2IlvhqL%Bvvw{(7k@72?G_WU>ismHdVOKaS|r6Z0_ zO6zfqMMAA7Wi(>wil0@BcojQO=^FVUwdDDT%78K!osqLCN?$>pI;s3@oEL@)HQ4{5 z^?Y8K?=h*}`Er~WW?tg+!tw(g#9;tHo*E6YK_^toKpqN^gl64FtWC&d%{q{YExj!= zC2tlUdUmok4yGUBSkfxmgVJ?|lpJi^4++?g!>mp@kk*`8lyH9V?t~;V zzL2jdQOB`>7Zi0E76z*1)Y#OPR1U@kpOAwiZjZ;^8mTy|S5f+#;@Ne!u-|4MkH@pq z8fO+avFZwD=7`?{KBrVPxB8PJADh~If_*YQMxM74n?=%ULU7j;z}2u`eK4P)!T0rX zfDfYrQa*mREiOtpPtnWJv8BLdAWf+u`fWRgx-G|0SE6a9vm%-Q`EKJFLWPX6D#{tB zP*;W?3yZ{mN?4TpYP7=kndv62#Lwp_CJTO(2j5u?u@h)1;&PXm5FP=!GklK@287YE z;Mobp$Z97LW71g8dMvVXVjRBddC(vdyFf({v z3@^DmJO|Tv=8(m;9gqa3;VM<$TX|g9HSZQ_zLL_C;3qDb1wYdhh$Wti4wpqjgKnCH zCet1vyO7Wc3GFS*OSPlE!j{0>6S9ZnOMD)!vs}{Vk5kxl&^_BavQjqf(lZNMb?C;l zoe$q0{PhUt++H?RQJ(om;A{L44TmPZ$D?oa<;1fkWQYVGv!~e{pOv{@AU!sx6_&u8 zq*Fj3r8i5bN^3FS@d$=9%PRR%KMeTW57(k>4A)dX35G3aK->(DawFX5w$6_rglWBw z=#wRUT=F!lC6mT*#~V72>eHDu`;^fmnXNj-?y4)J@C_9gqRJCXVFD2vwiT`}^~WWSrIrsD2Sd zArTHy1%k%aEDTn5f{dd+Y#`XYRs2#iKpWh4LC>*Q=afb_hx9;wus+qZiP5_Ul}Chx z53~Nhs%K*ZSADQK*9RjDuVY;TzP4pa!<-h{TCNi$}P6}qCT*2$p+PwhQgW#Un_lCO* zOU2W{dX966$!s*N=c$JE5EQGC9M2mzTR=J^y|*`1zC{(&9t&!H33gUp_t*`5}n}rB0-E z1~FrMv`<10){~yPPRLT*8q8{64C|r8X{@I{65Y9+4D1E49%lZp-q_?h-+q%BZ$tP%ODk@`p`}zJLJ3 z+0Kbk9Zs9?g|jKu%NAoYbq&Upd6n0+;ZwkK}8|iO!b|C;C0-ypajZl15nE3(|f{2PC_QzVIT0~j(>T%2%b*1PF(;CBeJca$xbpQ;X5yvLiyD0_{JGF3F3DJ`+&#>FF7*NUTN)Ya)NKVeKO(_ZSk21y z?~v-|=iARcF?U<>d_-)?n8;5YA82JL)(^=LAjg$HG5U0ZJK3_)I z%jtwC;Yj|2PGl3|!IhqjG{TT%txS9`MkfC*+V*UepjahhL)zsm`u6Iq1}V?@8#)wt z$Od8?Z3aUsVYrwBhHzJL(Aech=k`*a-xRud<2l!4pU-bf$8H&*w=M(0Km&N#2BYay zt;v6m$=lqRbk$P=LZhq3t?;d1z%Kp2heDxr-%GYjBf^c@rCV)Xq+MDlg#l`lics5- zy)m;*4m+caYyS)6+_q)jyhQmp;n77qCkkZpnh1U^r%}KG|A=&y*uu zv(@Oyaq#1vR!M+qrh-;bgEP5J-5M)3k;&Oq;I5LXfQWadb(~9(sg1I>Qa?pyhl~cv zRFFp^o009*qzJuF=Gp2@l#xI+k*UyW3?h&G#9TJoGZyEN3qFihm1vIecA7k1+Y5i5z1w8w_h;q<>igf5z zAA1uyN_@Yxea^OKh0O2gKG%2lMApS@??{)K%oOST>3wPAIMi&ZZ*AJ5|G(y zl*mkBddpDWs&@&=)1YM=$FC==xxe$gt67LhE7L;TMMDKsWmN)2yr39_Ym92ylZNCj z+)GlnvZiqfh{)Clch}ho#9X$b8xmy3<-}|xCu+^c3*mJW-LMmSz0{7dNN{YmA%kl& zv@6Oj8`@KI0DpyWu}N$F<_HJH;}aG^YXtg6qytU{n2?+dCL-HdA1=l+?)C{{QA}{e z01IR`h^{Q}&}j`GB-^89JxCtpvWn^(Q%vU1Er>&oSKmk`^QgYjvVx}sWLb5S_Y)CY znmO_C@_L0)Cp$GH^?T6hpAI6{lRoFLelo4b4Vu5%eSIgb^$lTxK7uuwoDTI%8pdG_ zS;@`%#K`=FK1s(os!vin9L)j;bu1w_)1y^D}Ywd zEecTN)BwtnaYu!w6uz-KlLI(ZlZ=fpIIucbUpnDSdvZ-GrlN{uJT)Y$vwn(#WL#QP zkWU!TU44b&_Wg)LLQ-_d<63VhFyuWvG-npfazTo+`fi$mGXBOw$RSv{{{v>~bza%m zp*RVjE>;5hbnz1H87TPRZ-kYFw_Q}LU4iWxIAAlsXZh7k?N|8~m9{ji=lIo3=*#?S zPe=wPl~mJM(oCMF`-o=J@L>E<{N&KXJ?#qNbQH9QTE0v4@NH&zOpY8xFf{a?{9x_BSMcR$Y16X3;{fcKz1& zrq3*fkvRu`d!yl|O>b2#Ha*NV`^lzndO6aJJEpr7zVUBx%aOBRn?W(;OmAEPLUae} zJ)g3*snX+=76$8l5eA#`MYN5AYz73`N(q9mrYc_ScIS&IA}DW75ltLFhE!N>|C&JZ z_+ri%*@oV?MjDh6eQ^&C#*`mjnj)d@&BXHXDmkV6; zw*(QaxDkJNT}v!CU2+<0xGgsw^ikxN9rpWDW?PVTtM=ECIL3KqW$gU;7e+>YgV6TjB$A^=5_<)f4u$k`$VkF=!jLk4DJ z7Jb1|H-$^HS=3#H)ctTs-RoS^WE!da!A(;4dLD_TZrrLDlDt!J=xDb@MoHmQr0=DO zGG0ni##>0=jxzQ=05L#HZlv$?oT8Vd@81&|K(EguI)pgM&V@rG3lF(*zKinloB%zZ|_#@2-3IiMC^!bx|Jh}-*I(GVsbA<8IODK z6l1&tfwy8Q7)bK#f3duVtH{%-1=_F--zy@H{YojW!Q(m-ePzo8?HLy(3$v?GjHSR&W6X~zgp_4{QBSot7H0?u3+I-f2e#!V4}$$;7!B`z*L(05FTP3eUf5@KQg?GkdAB*ZcmlTHah2%@b(-&Q<_ zpBOGgpfBOT1#cyhx8-t;b{t1R!LF9rdT;@Hir9KYpTs>rs!xj9TbxCFwRj5IwRmc} zOZ(wi+C(!~8sl9Ep%i{ijLH>pd6VL=^%V)9W%YRLieyjf>9(#&^yFOvBeU!|Cisp8 zC=+h;Fs1h_gEB(rN?T%y^y$kkmOA5CVyQUMq*&TW;PreZpGy9&FGxhq!kGA)rBun@ z^%IviSeElNON*o6u%*C$$l^7UK{E-FiH7Z<5CB zpE=%Y@~K*kJFZ5@#W>o?VjM3{H=_QJBgQesixcDiCucq>NSu9sJwV22=-iiU@u;UyF7=qLsA*TExQ z`cAvxZE zP3~3~v6-Jmxrnim~u5vCF7$O*h!)BUu zTb{(%(45NEj_4ER=23lO;Xce~b)-ei9wSp!r0hr{W#dsYih{D6LXZ$j zCz&|_@)$?^tfUYbyQY-V`-IN>u^N6k&uOV)vXWwO&Jly7gIQ9)fMD~9EX==kA`7$E zi7Wskm7j>ou`$O(an4dQ8_JN{sE_g7DmGKD3 ziC`MghW;AAKkb`Mq!cs;UpwqIf@H3=FOx_MZNGypXnw%Z40s-#z*&x#u!TaUVxv5X z1I=?t+BmSXadnH)9%_yD zk$UY9Z5nG4W0k8t4Ge2IgP~ejTtJ|0k5rNKF;Z?YqBPQULRIUShZzrke906aWLx^Q z<*7R4X#&zro-NLdRV#8mNAkV$)PjIVl^$9qCAYOK>zk$;%QDBZ^jtMY_0GC6NoAI& zkP1)MC1-NT9FcR-v{slMd$^-`w^=mfI`+;v=g#KVZMOJQU4jNPVQZ**+5Wxrl-kKA zxxYOgD0koZ7Hu2oFR)$1MC|?Z?G47{n7M^%h6%Gi4=_b|VfsKI8{4kmUW;U7o0a`B zb+dYYmpz*sON;FYI%T4)&L!|+@G@0+pDb|uI`3_P4z?L_xlN4QYz=`H!P=CGJ!da? zg1}jK6sDQ?$Ujw`;R=X+cWs#Ywn%xtEA?$}nM`K5DI@#3hry-!=QRYPISs(37bQi@ z&(hAm-XWLJ($EGHsg~{RYxL1%={U`BvIp&3VkCEJB-`h_p@)XyCFNer4MvKGNS(?; z47SNYP3(aChtb(e=P-0r$iwrY@Cc+=9;?BD2=oaD5B+9YQv&Vz`EqJ7CL2}7OZ4v`CjbJ<#yRNAjuBBdz;4sL&9@`Apu?h$! zs?pPO-Njran+rw+Aa#BkSTJ41Yv7a1P8vrMv53~^iKlf!dE;{W83FM2dum=#g)B@h z0`0e1`Mdc{#3+&q(C8Ey-fx8v4f~Gsi9BqQ+gvU*ye0?4;{)bW1(^ohkadhOI8}Vh zoBeG;J>IJAfc9uIe#zxCvPHMf-<}f@6Q(PiDdlf#jgr?un4Vk(I1gN)D6Nqx*bI}O zQT{e==L_d=&nSO;hQaGdaRN!U@FOg+cO2QA^S4|6zqFV}_~!6UL>mykIh+%zP_o*# z`P+sc^9R6(B2oy*4W8jJEU16|z_Q64)Ik8=46R|s)sizUZcqpgZZ`JSUZdaWprVS{9& zVAMm+Uo0y3Q2Ped3n3moX)$g(9=X@$G97qS5&~Bv?Nu3~do-U`bhR6Rse$i)YdVKw z=BDnBvTkuGC-{hri$jUVgT*_=#3Ky4ulQ;OSNEF=?Igu1IAbTQzuFYwu`>cZ+ysp* zC`g1V^AX{(V@e|_!ed7!If@b?*uhmscGM9bI{{9rGO{G?VW%TJdZ-ktKjJ#>n<6|2 zlZJYP^dTFACb$yy8Fg0b~)J%=(EemQ9$*?U`RCIKD&msb% zfelm&bR_CloKV%u5~&aY2~x2Is|*4%!75coj^HT@A1m18BKVU6ig%cFND$ukl}NDO z#LDUr>Frq=48C1vYmAjSl2KBSKS5{&?`YJcpNRDd}-NJ zAFbNs@dPaLvP&bv%NHSyXxc%`SNkb8xIdLegHaCnMe>Tma*0KQOkskrqeIN95l*t& zHXp27;v-{yVXS%y-t176;LT#y#0zE4omq8j4J9$L!z^OvkWvTbNgC{-XIucwD7D*Y!D@!<>bf1(iv=inwI>?-AhY;#HE4R zWpnc5=vJ2!X7JgdW0bC<`%Q+|7n1{7sALa#y1t}C>#;JO`eD+pM%BZQZgd7uQ1U%r zs1L2*bc%hxP`@%P#%m8r7eG^$-q#skP3U+oT}k-p`a0dcrs;0jaV^UzT1gF9G)h#u zMP9>ra%~6e!sGyd5rO1^;=8`FBQd(XmQ6P-QfcC1#F?BydFlo2R;zMQ6p`>u`$f|H z=X^TLZY#NB8v}nM0&=aCvd_@FJo_z@7duQx@*Mi`;9G`W+2jgIH$al7-q7g{JCzh+ z8U8z!)Cbd@z2y=_MO0yT#M{mBqXz-h0t}hm;)$XtlBFdE9)E`&dRpZe+k2}1kn?li zehsHpmfc=|W|nt5`#Nm=S$bO1h~le9&zKMf7z0 zAi-aA)By)v8Yqve!{FnZo*R5eYIktQ;^MDxM!*BC!*=zYB3XHbrpU1FS?vmlZ@b2Y49kucl4m*x#MTA6XZe~<4?nWOx3_Zf2^zem zdf3Fk=HgAYk=|ra-YgWlrFc^o2($YKB6{~)XA1)Wl0)Zags`I~c-VsRA9rpE>N&}-D0k`hp*D3eGNXhDA19iwn zW`XyZ5=as14gRDq49zc52MS=@VIoC}L-o!t0CoKv)?74^tQ|E{@Tb1Nrr&G%cTv4Y zSW3%#-g98J7_zFn*|d=T0U!KY;%S(|9KZNrbo#{z7_h7%ayde41dSuC!r(D2g=VQ= z5BJLc1EnaAFue=Ofl8=J$N)`peSku*%M5t67ssFtODkm+6jShWcoO=q}3GI$GrWI80!~Q4eZsEJ`x8+PD zv$>)-6FF&&o`pv(ZZSLQ(zO^^H!osPolCJFOogTEHV9oW)+1bARr8fBT>Q>(Bqx zS38_>D*zPL3B9A#XT-Vs9l)!1*duiE(1SeD9lXiZH#G`o^%j3u90UwpXOa4#APSK% zlZ6zr_t_Q#7uTz6>u)#L-<~w=_HY;2;U^N*U(3s^!5jHt-@J~GK7hQX9QvC;dy~Iu zHP+(Iw+{P>=7Ugu0gWx#haP9j&kybA!BZtRibVbT72c&u>c>F$c5lCx4cgHP2^=`7 z`dUJ^cT5E58q08SVi{&R(YfQS?}Ck0R9|=qh^Y*axpj3q|3ns;1aVRQN8NSqxvV__ z^5=DJ0_15O>ju08|95*NLJZam!^v{D)91fJhfMc-m_3T>-+XTx6MMC8BjZN(FLZZF zSkP_mCM+nbPwMW<1YSw@5MEWE*Ik|J7lF}S`9WRTrRQ5Xg>2Q})EPa|pMp~#ADlAKfj1DD9$pRR39b4gS{RWB_a9 z{`T4L{d>Rr#NnU)5764y3MH5pFv{xJf9|PYnUROWzkc`U{?%`~OmE%UOkS_=4dh~V zie@NyN@6w7XehCoH98*F8?)m8n2L@suYCNrN%{C~ms37|dFS%h$+^HFE}yLb^3LVW zlXH3V<($hu?`^BM^zNx<*l%6*mYL97I)t{w_8b-~-A+*wH@KzJG0&FReZb1pR(gp9 z2p-Yy;E_;)<_;{vBeIHv4)iW_ORF@ig`!2`S$3x%O5@SRl^)}qk!X#OK_gjZ8g*pg zuP=%)EFIt?)I43Z)?_^_1c=aQRuUbyFS?uD0kE`ND)E`RxQ&gBt=*bCWK+FVwOh|Ol*7ieWM z))kbxUYYC6`@aG+eOJ8n+`oD1Q}EJxdFZ;;6F<6<#OhfPt0h)bGu@3O`wZ4*Hzv_b z!WVqM)tC>7E?SLgv$Px2#vZfi;5tth9XUH>(P3{QUbHMaee?xWgds++>fjLuis{6( zDYtDoQ459g##ZpgmiD;a(L1ueV%I^!n&#bC*d1ndn%z644P(m6D+n z{g_6&O{gHU9_?22O`>N*-_k1qd-IH%LS^C<^h&>8UZCGO33PPV%O`jI62PrFP;A}+ zI-Xrjih{bqA)aG`4FG~vPcsRcA7rR%Z(J*Wxms|&kQ+llALZ!3}Ac(sD2wSq1)~_jAcQ7$zR@zLLS~u@9x^0P@xR{=mWf z9u^x3MyBDv{d1rEahyq@8T7Lf_567?*0t7KT#fZ^(dZZSd?>|k@%zWem_}F<6%lG| zGs2P)TC;6NSTaJ}bn1TST!-1a^LmiLPlK)}fpbsC7+3v8kUX=Op>(yy&oG?Z+y5BQ zJcf&2(eL)ljv@4;-^ZkO2xuaKE#}0^6xD}xcVR;Bu65Wy5J0vx5`04MO2e)7?o_^E z8zaF9y)(^7@SBrUVZW9YR+t&tJBpag4{BkfN3GXag%6V|cGjP(f24F9y)$v@kcwrn)WfJ-`c4afv4L{dikt7>89B6RA<$0y6H9MahBU`f}S zeBuXaMrdxLT|Jh6P8nBG{e29*)usc1<By|tSpp0EH~ZDVY#VlQ%j)LKNMPtX0!o-bJ~`dy%T1h78Ej?ZfWLe zEoW`!X&G|l8Z<=C3&wNfNH>Y4Q7`Pa%XTb*NF})`>m-L>dxy!HjoDeO&XuW5fr_0cL{`0PK=7Bjm z-Q?Qn;o88@D9;_FUw#19>Zs;@pTf3+Ep?9Cv zO`Hg)((h;VNn!qZQ zt{tR|TDPJgusm9Hd9WPOHHC@F(L6Uc$^-kI0ZPi~tzEUEDL$z;0Rc6GuLzHCfh?o1 zN9^gWl!(`@&KGibt_)z8#FfcdPXc0Nl>@BRJX4I-Q>lol&LRDcH$*(dC@I#oP` zLsEg}MYZEV^-pMMt;4~wYL(EHC+ddz{dn^umf-c%T0B;&MSNoF_gG24I@k@694!bx z>sCs9%c!Nv9RiKy9bG0Kc4d?d9yLmRn7bg=D;J@NX;v@*Hb2RD#7jNfK*=C{rv3Zr z=EpW5T<^9(xZX`5EUI09URx^RDJMD`B}aq()ZyG;jKJH`LV0_&YbclXN{I}yxPM{4 zM7`pD*RVZUVZ7=4pQ9*^)R8W#3DAAZd5 zKlHD8m1Y*+j*Qxk1h3(eF7rO<^w59*iC_ET&i(5@_e(eO6j3ca&2a5S9x4F2_rBF4 zwfbHf<@>z28@_7l_6q$Ed-osI*Gw4Lw^2^{p z_$Wd^ShXF(SkXjy;A zp~K)@<*<0W|6xZ8_^7U`>4ky>u4;!Xm|`B%c4y>!4pfIg&3!r%Qoo@r2OHvH%Cg@6 zeIC#UKM-1-DzTpC?u5(mH zz7ElsIgl2X54gKH1sGMA^BdmGmd9?vP~wO#xBh>sv8KVI&avO^V7G258x3Q*v2*2Z zoj&iYy2QTDtA!4H?xsJ!D4>W?7j_Lw93Pr*=GXrVb& z2$#CCSh}rnQC7{O+#Lu7CY2FxXUtNRkOiE)0uc&}*JkUfQ*>Z5thdGmc1#`Vs96o3 z1u=wLLb^I>McJeo71E^0QJglZ-bii&8S*YyYotyUMDII(@A8ZfdP?}Dh|aVzLa?fC zzI{m(4-6xu55R#_!(PxnnHyLgE!?mU)Mm9gNQiAVoE1qX{?oy{-gMwaU?A(*T9eUXD3YtfA(^k49>o$Tzp{0x+%(M&`V^zVIr7`s>wJmti7+^ zs+JcsxqM%cOBDmiM3T>-2>LRWAncbm0VRYkgvt_O?QjM<|923(eVz9Jami)$eD`WU z(dKVcacteai|&YSxS9{dS&BLHKP4^VUpJ4u`3&N(nM4j`H?l0dDMeylXr(Mm?XQJ8 z#}X_V4C5ZQ@qP>ve#Y0}72gusHg|e7Y^2;c36|^trcMUNa_8#mibbGA;Zh~Xx%qf9 zj$!XExjZ~FY2EHSbE0J`1>kmbG3~Be@fDyUvcT(UZ0PxXjgkPToDs5CK7&FbD4r}d z*tPO$rx)nkhSjw$B${nIBiJ!nEW-VcO|9zWCls(Ln{Z0FoB=>pS&5B*T(@*ou1bV^ z=er3SnT5RS+6T#Q0%&r}RQp1pU~`LAH5 z(<-}>R=HmX*MJT00{1x18F)}8%G!`H4rU-NpM>#(#BH-tSq%JO5|8}I29F#94TsCf z$NEIZTIX{=_40=+`^$G;v&x%gJ3G+^t=e_ z(|QeR{R%e{c%($qG%6$-TC0Bx14>zSSnZtFPanuKk;(VGC-saa zYEef`iiN)w6^ic=%(Dh@X^T%kPFO!H!DZRGkf@I|k3imr$ys2sUZ{|&0Kil{gS>*A z7Nbpl-xBpD0slK$$he;{sJ>5Lt);j$AX5SL)(o~I*=KIa)yA7CmbaJRmHc$x%z?m~ zvY0_BAvf>JO8GOQ61Qif^jl8sZ*P+7QIY~M3jZqO)J`z$mV5g$J<+D{Q&_9T{3;SLTW*agmPumWCJqmuSx3Q8#FylFCH`*>6xm51rvJcbkH?UeE`|mQ=0S|0XMkkrA;9mWr*3n2fJmPX4{#H}%3Z``_c8$; z--X)j?DE{^Re9M^+k=-VU&OiURKgd)-AnU!8kP(ObBXAkFEDiguIF8RImMC{l(9J_MiUbFaOMMb>5{cbNOyfue#M| zMfBv@QqsJMo|~W%A4SkDO65Z=PHiL+y~VLcn3RZ~&ejmo>w;>W%Jr6IfDQyoxBYL}9nR|9LLdbOw+Z2J$2+_)fKK)E8ui@Zx|qM3M`V^2lq`3KzWh;1=_Uqw zY^_I&^e7u!m_0`Bt`v?3xzj526S+IX%lQpbDrFOB%+UZ2rP8%hz*LQXc$s z7eAAtTa%rgL3Whgtjr&%6{bks0bYJ`$%`N=N4?O;$NASW_}7slinE;X1B|MTNaBxA zx+S$3)-V~i^>I8ir9&I?EGFH_CB%y4~y@4NORIy4tmN{V6x6@ z!MX>vQq*vzM#>PbZjdY&atzaG$*XURb$P4Vf!LlX_eC&WH-=P2X1WI%?EX);yMpz4 z?gP-l$@|zgGGm?(#ylr^P6)j9U2WN|??Sq%Y@%@r zln(>S!JqM3KE&6RVK;-C<&|Bm0cm3)Xh7P@+7B7Fb3(I@a2OddU&k^5QB5)1GE?j= z?~i1z-6CN0nb0=BA#}2RBg@8uzm$t|;{syG{HQRr3q;&E0i}2S+HIT zxo%pWnJ!KBu2$>llst+m3;`c$UMQmaD$fTxsy3W-;L)I)$2{%RVk&b9*=RPTFjcM) zgQ+!6F!L($dg{j@*;oSeJxgHSr9G;bXu%NaD-U|Q^flW^U#^dF4NY59)WNA9#F)Oh zr)lr1TzM`@Ui~a}xq*J8W~QM?FP}*g*Ly>|e2-*RRP`{%y*os?wel`4PSP;vw7QT= zG|aLin`poKeI8#eA^hxtNdK1fnz) z(*q)@m`_g%v`f^n0ManM7|3GxhPjCZRSQ=ARJdmaL|VYy$;<*X(k!kM0PYfb6rz3E zsebtOj52a^*!K7C5fk6}4!fq{8WbY=SM zZjy_~I^Mh0B5L$*Qkj|R?u5LoR+gvkY88Kj0OWxN9e~oj`&R7v<|p?BO_oJyCRD`x z1Tve4Mf|PbwKc^1Je`W2ct<76BC6ufk4n_kR`L)8q5C`l!w5o>QCcUxvgyUyfh!0o zWjUc+yqyXi;u%sa4<*5VJy|*K55&7~8F`$w&TBKooizCFBozv6yT}sXT?}Ux1u75$ zAQo+TVK`tWqbo$_?jA|>*cp-n1oGVi#~V6#OSV{0N=>Ph(6s21>*@(xWew0kCfcC6 z3(&|_iy@l^EflG|(tBwd+Ka7A^!aXeq}x2WTpz-@ENed1YctVL&sg?h9IYyO^*Fpl zu}L>AJ7e%7rf3o5~(*i-R1fi!RH zapov)_~!!tlv5Bx{Ih(pC?1d}Hsrt@4ntH`8n9-;Sd&?$l{6KlDa4pU6=I@7CXRx^ zV?3hBo68RH<4z&iTKNuhBCSuh58V~!p<+l;p)e1z{jmaR9B?&_YQP6lwP<1eRGN8Q z2bDW%Z8dAVH-ZRhZ`VMv9}NmoqrdD;!r2zKArX zQnMu4Kbb1J)z3e?5uw=3zgzuS{?(4YROqbiFLijO!Z9Nl2y4l6zxc_I|Be%i-zhzt zg`$V!-%qQ=Tq56wSO=wX{vABE>7Cg3+@GPpb?+9FTT$d9p{_&F?j4%g(Kc*)_mwu{ zKnD`yh=6XL2qlcmk;8S`6MJ0PsGT-`udM7GdaUR$*(~?9aSV)Lf+-Qi1cbYrGe4Y1 zA*}CIH*c9aN?%}aq(xj?Cy!1xpPz!Jkld0|N*5PDaMAc?Y3=gh9QZ&qbhnuAz(Tv# znIGE-sqalWE$&nA=Zd45XBlpLnKz}yxuJf<<+mD2p`lGff?>NME&Lb>F-B#cu?;5p zMIqH$4f~=)L$`T4Var#_i_KEJEL)#Nu;0{KiNF1ePyIOYxy0S9b;$SsPoMd1ewl-4 z^FH&TG*fxM$Drt<-px*SgN2%?8}zSsg92UMpxN`b%kn}usQF?ZYrSJ32i|Q7me%-S@g8D$6}mMl(5H&QH}eC_$w*T=C<{hT_gga7 zxSgQtL3Z5^1>%HFt9prYPNPyyae-IZiV4xQD9*e0)uthJt~YTXW7Yynd)$*-Og%YG zF7>pg<~+PT4Bcb?pVI`?duznkx*b2C+VM~n_X^h2iaxbzw1)o4x-`RGypo?WiT2fd zT7?vRAAxq^9>S!HYX0r6i3a3VS%`NfCefrttkloo&zq@E=aQ0DwKwQhBVPRAc3d`? z=iHXea~jt@ZB;!+^{bsNIV!IjMhvB9r|ThCGQJRQOia?c2fet^dhGUkY*m_oNWby* zaIMTFvKktXO{-y%mtd@d#cbrs*7C{ASiu7ItGr$Ry#6aa$^g0qU?73cY|)fPR?`w@ zv}#vKh>Ir;D{mLgJ!3_r+`3Ff_kv|ABw#EZu$VsHdoU1ViXB_w zuuwkZaB?_AVwDi!&u_ZRlN^DtP`&(C6oyBKF|1iZ; z?F~yTt0H1p5RO1hIm7}|yQH6kzW^c72L9&vaqr$YbmV5B-rRQ*cfc>I#u{Q^s7fEQ zIU^{mJ6P7QIa!_&xG*Q%w#`(BU8uF}+9+?dzut3ytqw37L5LzkY;(ElE{>pZ9`t9b-- zxaK26j%vaI&A&3qser^~VpeaVX@)P@uIkU^Xv-<1Wy#V|F=A+_3~_(c&I@hg6NL%< z5SrG|59%laH{=h961@Sh)t;D#VneLWv%!Q;-qsRRhVXDe`5~*u1!O%^_!#mBi^Wyd zW@HfrJZ*PJ!17HEggjB-A?DaM_gIg7&5wy9$iA`o%aZdzapVW;9GdWG$xB%3+r>=; z(Gu7GDzXRvdT+Z1e#Q5y_jY{~|JSdteDUXJ-&S@1W|+q{*9xQE9uP%hz#Eb~_`r&;El(28|B(@Dv1QTC6GD5Bw{3L*59MQJ=6MQ(YYjrB7>nts~Uk=C$QG(Poy?%En4u9xm6wW3w^2BM>trtYL# zbGZOERenAtI>+3fiT=jQ?xmFC`UR^c-&b@*E#e1O*00zu7OQUP5xjxWoN)bgDN^%g++Circ&yhtOD_zk`2;j z<--->eW9o4FQQE8v>K%wKeTDjyyzOGBKB-a0mz$}Fj$RNmf5^#zOP&MqMVbe#o|1c z7G)13R(RRf#Da*&68V)lBCAG-BXS{;ucX^p9{45iHpX;li@5vDf$FsgB*G!BzF&*r za>#dnkqzXB(I{7Wm{#x*H?6?b?y0)Y=i^2XmhA3YZ$0;OpZn0vE$PkP#G6HaQ_Otw z&42K`D;TRsrN=1`X^6{a@YBjTLiZ(1WUagwV#UYW;Me^*1Rl0|K=Zg9^=i!>1s@$y z#h;{@3hdNHg_y3+MnJYi9WTa^qet`7=(U@Wb{4<1R4j>H%Zcy$!9+<8epa+nE;>Hf z$~P)&c8$LAb1dzo)MmY#THg>jd4k98U-f}xEQ?bwiI3FRBVK$wg@kYf87_vTldKV= zF!&|)X0QGi__nX}CrAFc3Bx$7l_-r;g|?#9bdJo_CH1$jL%N#Kh5O8ajeAEt>A1`i zgZ5_cQtDqWcopIWw1lVA(rd-fwHgd-En+jdI#P_XZVxq{Wkkl3FQfVLfo>x=*=2+i z)MwH4H^l?=6dhXHMTFyC^t*`%uod26kJ{A{7DaEI%cD-^y+{5}k%RQ$*vTshL{~39 z=f{$(;sHE}dq)^b*f^L%&1)TrNkcnFMZhb$V~ZRQ;B$tG=B+dot-d2L0meavoAZf- z7WqeOrWKMKuor87pF|*^@*~%6zv6r~N%=L0Aky4t&sMsPuU~3Kf8sVPEJdde_caUP zNkWO`AfO;I@`6N~%te0EWqY?Kk1bVn?A3eqf9ittCn~ z(tnt~LaV+H!TOByAH%H=cBE~hJ-}{b6!HYCH=N+=4J89{(Y+CaBM&eMzlz4e@(}b3 zdLm9>Vlym+r$Ado1u(o@*$YG#fSG)Jt0uix-U-$Lckqwd%{uogry(`|>;SImj>2hq z?Y?-;3Iu?1!)z;Wuls4q-rUH5MXwg#Gq<2@_l~?l+HHQm-KM`^piS83Ev#}tW?i4a z^nN~o(0u^%gG)3fvrJ+l*A97UP5KIEt~T(b1c3||NA;s6*D zm0cJ6`)117CSt6ox*6g$N_`~&gbz+KF=9y+P{9aWF+ste>vnes|AB|K1&Q+bPetDP zY#d%)cL+FNn7DW=mfd|FnPnNtoL9x)E+j{QC*yL2rruNF4}S@{V`SQkWXkTPr(22Z z;67cza|2iUS;WBS!F3eITEw7)`GM8k0WaKB^+Hg9US>g|d5aK#QLKdeGujuQq2wwnbx6T4Zi4??n=yw_y|l! ze!C5$h+QH)LQSugcNjUmI)++?C3V$_MCA41fsA?{-{4Q^t>J1HB~e>U3{tty(6!Y? zNjF-EE{W^6b~$u-Z+R_Ye7x{lHju1(Lq7vf>Nb2NsK>IUAQ>fipTUYnIEW0|*`rV$ ze@@$aT#xP@x0cs(54j9JGdl!V5gT|DDNQeE`4NoE*u!vA+w zIf#vLted4Sy2LW@uh@#F=|y}MO)lf>G2y+SPsTrBzYgHePuS&=}6kjb)KHLQbXzM;gb$rSK-Ag9jrH?FY4h3osl|-@>-x`g0D9d*; zTPxDpiQ&}>qKBD1nqhfbjBp4Kc` zuvNk5G&LI1Ni_TtSUPyjmYIpP zkcS}_H^+pMJUla19_BQPPKd*7nobgjUqjPUNbpmwDykQjYH;lga7m8D>L6LTH19Or zNZ_*!ydde6l~jGj`2eD-20DZ{G~Lz$%twnMKZIK$295PBLTfvUjsY2Hpjo#fUSpyR zWL9gH){bXqb646KK39o(oTIW3lS;KJ1b7xpXl87FK2j&OC~WhNPx67z-6p?6R2kA6 zEI4n}Hzl;nq=(R2E>>40bYYQ5SBkwE9omU`Ow59NolkI22*AB38G*!`FYt4%JX(ZY zKu`NRPcT903R+b04g+{d_9&1?6Xl?RkRhT05nB&b4T!+B8u-T(4Jf|f`!!>Is!zrKsILU=Vt?c-!s3Gz(@@(} zcLvKgWoKwg>I)a35oH39zBrr=2|6^{lf?A{J^$bFl=$)QDTHMO2@F<(M z`hL9Gm9`nP9sDUGYazGPGM8-AUE2VU~&w)+s>{=;KC^mwG+r8Boc=g>qbl+d~Z?SE=R#lC_RR4 z!E?5wAX%>+FlpwvH(n@^ME2`EG`{UQus>a+K$obuawc>mc|!Qcr0JfXST8=}*yIxG z$)%BkizC{k;I?B!RO;x0(I!Ykq(nGYK!z9Im2Ql-lAP8vweKkV%JDfhwLR2`U)oHDN4CSNfY4 zlk=*Qk?&=lH^m?7c^ejM0ETo}P21oRmSETdYas6Yg}^4PF!AOJ31I1p5dG=;7qW|T zy3#$VBG1;pw0X-XKz$*%=yaG4=!(ZcQ&LHw&vEFNH<%)$wE%VBx8K8W%(fBNqLZNb zU7s~?awfFS_q8nOwre4NoYQvAx2m)J!Zgs-eUgB{706G1M#B{cvY4Sg$^^3LAv!1e zvuYrXi5>_dL0~0#nZT}FxbhwqaS;)0i5@%;ftA*R2U$ZvPRca?<=_K|pBK#se9mvE zr!&SG!oDQHvk^Pp+gXfU4O|;Jp%T@=h4^elT$`9R7G#3k2xHNcmpjzewAzw;hVDp;fB&^ilKFD`t ze7eCU(_yg|Rg+YE@8#oI*OB3TLzv|+%T_NKvJF>`x30t%I@Vkf4#2}`yE?B@*w^y{ zT~v>MfFEc16BWkNL0U+z+#5ee@V7oxlxq+4U7`dDb?Mp;g#E~T)`P^gk{%>>mGmIt zchZB7_cchE7Eq|sas#wHCS*81qr1oY7f^(^VZ3Xw!_U^2trsG)M+P&qwQ z!$~kWK7+;z$o2gc-_Nn9sK+rgx>}#l%#5zl=b4!i?0v0#Zf5j#dh+bd=td~61^)K% zPci)C+HxB`ufWWK(1#6wq^?ZFMzFy1MlkxQ%)c4c9 z(a>WlM}LA_8?o;hQ@Q#->H66+4Dga3q!md#e5wr5`gngZUpp8=vEHnUh z*t$aJ>ZiGq;k6+Zjy2<$=$aOBM6{R7w1_jDTWXMCVPQ{Y<^bNYIq{w)wJ>nf32z>+ znZIENEm~YGwU?DV-$99!C@kdxKf(f&ur3!k0w4x&5CD$P*yzeMS3FJL2L#V_C-kUi zkZshg6)Clp9ShB2vjN?O(4^GMLfu1&k&vO#@QE40)`+^GT=W=$?(4+LZuMI%kQd=! zP^+0Ihus@H|7_;A;>&!?Z3D@;noOwv*xW$P>?t@()(rUD-n(LhcpQLJN6J%;)mWJe=9l1D*Wxx_by`aZu1 z)+;S_wtIV~QOzfUr0{w!RP4E=Vyj$kF>>(_8Nv}V{gYZB`kD0l!>!%@k)+5U_88zp*!~5r2%L=bd+BT zR3MXVdn2!ZgUlwMYznx0JfbMZpU z`(zVkyikx7+IoRzaMWy|W7BE}W+RTx05(+1gdH9q;DfUdy=n6}u8VL%jpvWDG!*R_J4XGPLA& z6vcX~e_Q9LS!7LB^j@<+AzIHwMe~(c_oP0%)u;M0)xV+hGrEo4k*yRv=8?pO4wc%m z)NOnqZB|T6+L}RUMf!jXtfMaxyo|;)NIQ{41xW&}9KPY_25+nu7eTllCJ=e(r2IYu zBxD~xsZWOZv_2W~MnoW}d0rDngL@Qnv4JFT+!Nm0`Ik_<4H;&F5qB`@{KBjP!6X#s zb<44$dmD1&3#gSTPd zsj#_<)q^XyR}TW+UOgcxVhi}L&y&5xTyP}QfW$)EOKm9I*Lg7Q{q>S{K`h2FXufLR zu*S4){iwtk%EXZ12(!0>6aiJxrvE0UZs%JlwVN=%XfWT%Tce55&j?lsf7z`481;$1 zM!m0dye|ezVeY;yJ?4$x0d4+xuqXZqms4q!5S-f#)Yts?7lhx&f{$EOC5IU%0dm076uNj86wzw%0+P&1oh;6`E*}fq|Bdp%lKkFYD zji8hLdsUQLvfJpJ_+)iPnmH_fw8rPZ;B#+gHB*^S2vtQeA2A2pcauoOSZ(J8nq~#& zBj~pbmP^aARZ#}`8k_rzyrFrW@w~)@a{Gx1`Q^lfR%}_NPzU30weh*s#woSIHVams zm=Lhp*8vAQ3LZ%V5P4i~n2?zd5|q&eCd5XgPJUuWi3$0vY;;3WoLMZW)qnnvKk~z~ z6lc|7B(u!Y?c)O;bIuPiFu7`kccotIuxr_j3p;Y{v<9GOIIcQNn8lXIanw*hayqxe-D6n#xcr~ zh5k~VZ0*0#BADALW&uYn1^8fQcyb-0|^InxbX*mhi zPluRDwV!BVqGu;FPy2-EQEkn9PO^=Mz7vX;jjdS z(rEuxr}}?Q-*)RFuXjef<=~lxM$obraV2OPwvoEiPo_?f1-3xb+@_kMi7V2(#%D~1 z^=ltXuN}=u7H{QHx9D*oc&=o4u1tq#8r#y|dU!|NPsF!9p5jc72o<{(R(J_4K3}6u zVEYImD3$5*;TX)~)rdO)ZI-Q7>@P>x@9&Im0C->q|AZg?aj=EI&hc5f`09)USO{3a zhCtw2+@ttv84x_g5Oe>JI0R;2=THs7+X&|?Or8%2J10dRNqU+gq*J^Hdyklwpv*X=LjGdj*DO9QI zEy6y{n=}tSh!Qo_cSx3Nfw2@BupOZ0#p0y~Jo(#@hVCWqCAMMTrkj->hxV1$$!|~) ziRGQ@cLbDjf&n69&W!eHo3IQUv(@68SDl(+sfZUhW(h6pIFlw~Nqb1~Drhsv0Jtvd zrwkHjgUxVL7IiTkRq}!mJN6Bfs2=H4{bvGb<}Z9w5kJC8QAv?YqKYvh-?^ z|3Il6^aq#hgwu9s-Q7;Tqk+_BLiob5x!?n6BVgq9>iO85lo2Ex_ZKEI_eUr2=cKQt zu~Rv!o_U{Pr76G%(gPGtx;_fQE@lj9Zc=zC19q9}mKkWx16Kfh<6N^+46`T%P}|Fx4#(O5XP;5V(`0YFfYTd z;m)+`yR-~ii}o^{u*D{?;{T#|k-`><8P#Ai!gwq#RLVo4V5V^~&>&%?HcoCZbKq!K zm6aq*qNCtZ%5?H?2Y0*AQVC|I#Au>CUz={VYT|mBQK*SCkw(`yTt7h+Jft(n-*_** z7Fb;`(q#2>^#)hqyMEaH)3Q3gc6bBj3Jpmqr_=9hR$Jc{^%(Uv6doJC_Ro}0OWu*e zfX~24eqY~IJv?D*KMALVboKNCTI(&^|6l=)VsEY|t}@(Y8SV$eh<*8I@;C42EXd#}`30f)U^hf6<>(g>uVLvu^Tk)t4B$B16w4q+uGwkqHp-;^}Xk2qlL#)8F?G=c# znWx=wrJrdxoZPtihITv$KqTp0!=8c(k0LMxC?=eO72(PI=h zDRI!^0q>-&Tf+1Rt8p$XToG>sIk&G?B<}Fl3ZP%xGNGs=-$v8g57;YE)aavuZBacSDsrlQ;jK?3K<;CdgbOWtlhc0#yiBS!{ zQ-)1t|6^6~HzFnb@r@8lLpH+|gM%Q(AdgE+RmMivQolXe_}#H35&CCg%Gy&y3WUql z%v!)(DX;aN3W(3{J}2G3rQ6Ci0mb zkYr_j)z%n%GrHphSt9Zhh0|^be3AX(UeK;VmZy{bbtBndvBNS?(6~R6UBO_+@4|u^ zzTm5?uyneNfGR8<#p<&aOFnZ=6J9!|B*1XU$civVrc?^q!_nSZHX9b_ULO3i;yF+s zSfM$H6--E?S$m72r|DweCTI*)Y^J9fBkK&1RLzNrq3Py5t22%ONozrRJfaG!PRNpH zSX5ayA-}deew%2^zRq1~VP&%=^f1x(#?&E&9HkB@ZDXEm%_uDXtZK{Zg$Y~Its5Zr z@T0x3zRR!&j2MQfG`%ohQ77( zaPlyG*t`WjA192iKa5dJlL%)HjnrHK4)IXf>T$VRGE$^`+gATABXmhY`%X#2uuvJu zm|mFbvK2*_cx(Y&x{za+UXpJ~;a%CWd&daE>I$ul_Z_Q?$zt+0^{#&!!CTV^CT;Z3 zV07ORk9GZUBdzdaHhkOgw3T7qWz)kJRbXqEVVz5hVL~CcERUxO%)4D9xqwxD$yRk| zp%Lnp8~BsafU+;ak1b54yZ?Z{U@h{1w4i9^Jib?%7lP2|W`d_k1 z{i|JA%_gs|jMx`2se2!3$dLSq(~-E8#VCf{l{Fl<;!;3MX@im?K7&bps#n*>37)~U zp1iuBO?%j0U1A-xQ}^|Gx4y28V2U)r;}_U`Q661e&LOu~1W}NL7YMLI(3AE4KWHH|0N^ zDpDac)D~8}EUBV!YdzR4tSl{~#pA3t+XfM}cC|1f3K<0vT5E+Jfs>3<2HGhFS|GMs zth|g1Wz)*4AfNB|dEax-?Y`a9qhEx@no^&8&pqe;@x0IP=XswORVnv!I254RO9Iax z_m{_uRd8Z@fUo7|;wh=JU$*XRCB%+cQcA2l!+NYc!+Ok$U_E9*zd~+n$}sBDTzgy@Zb~t+lBq=V`GZo1DH6=T!zjb(v>=w0 zVO0$O5tR=vf92tq4!8h~iU=Pxi%rV#K|Pa-1Mi{?AI7?k{$w(QEK-0awfFVm6M)j6zNh*D0?Nb_q_-CaIv#v=QCQ&>o z!zjq13}^7tt{@iJCu=RE!ht{qbYKO;cU# zvWTInid4r&+stEu@N1gt>_}53qoby&>M^kvM{un%P0&;|E;Q90$! z(SjJfSl3VYGuyqC(}N>nYk65_$;9-NOlwGF9&KJo$|-3u#xl}icm|XhQ%-55uAE+U zq9v%Klu@mH+B&XU_pOq&%Xz^8kygC~A(2a}zR5tjy|LLEzD-%>I0?j#e#N;~yjMNX zbDMOMg1~x>uf^}E2_o9h>56@~t}6ijs;)rsg05{h@_T%=soyG<^cowzV2D0NNs&PJ zxkHaoG=En;;sOnQknyU^Cm|<^S9v!yytCwf{klJ^We?#u^p(**tt+El<65o|GXKAS zZjD_LF+Mh$BQJJ1z%oqeQW18-U}{r`g|Is1DmqZ$ky6{UI`$|Z=|&IyGd{+%!v?O| zd7QJFnPBvg0K;CR6~T(KERVn~-VOP^C+7jKRC}=4%{DLnpN8vOEFNMH+p=1@h#Kro z70LC(W(@8ei6Lz9@!I&f$U(u_V;2b~X>d#WT9RR2y>^B>H^+|;@bR7T+A<%ni;pYb zqxBU5F!pE(rfH9sSAynsEd3_8`2m@wy#nX;jjI6f6a%j13ykaPXmx`uqQQ_8uQjUY zxc@Ejah>~b8(tq@zRH)w!*|7(RfZHt8}iC<2*$a?W59zP1URiEs|ZM_C#$&Jon6&;^iugEs_&RVu0@-lM@w@p+VnlmcSv9I;>^^CB@e(%eOxmh z*GG9)ftz;Jbrk5>3U{nYw&0Hr3&7E3JP4q!_MF4jyV@%~Hw|CC^{K)X>JnoMUn<$3BER?5HPf7ee9 zk=8U$pV*9`)Z1{+74*$!5u_L!g6FnNR~;sv_q|Qiiz{t=k=EM7_fs?iJ<|lzVZ?O;zCRU*Q#Rp-T z-N7A0K}UbuYJQFs_avBL#~w0h(J0fp$>4%PYAf28-Lpn zKp$;>7Z0ZmhSRRE+0o`g>LC<^pV05$FE^@JcD@+)PZG@0ms8{&9`sP_wUlMN^n zLWp#7UO&!XMZCVx)Qx0U4-bMhBO7oBW@rB~l@aoa?6qeHi z*|8|KP3uX=)3hwweY=V=#)Y_t)7jrsL+awC` zRgy+QgMY6jjHQcYqofOEPApwINS6(GYy;^cdC6_0g5<6@N{hjgLOW#HSNtnj& zkfY7_AzK>kCFTZ7u7q+WT2e4){@`#5giWFa=e!D5fTg!K-^T^fatl-irfU@QZAlj5 zi!^5jog}*+L9+N)6ocRbmMmm?8SN2tW2{ozr*?i*1OH zLUbWq8j|=YBwT zbA4+Aa0Qq?zh0@3leDJ!LwdteKY}5U8|x6+R_GT8C_1FF=)o)nP4Pzb4l&EDqZxA7 z>w8Ebe}`3O9nIh2l!p>mOt@3!ITZl~u_TxDQdJ&t$%AG&(jxf|OU(Q6LlJ>X3R^C@ z4R}giGOTOb6_*TF4Bw-OJQ351<%mmGs9JH!7*b%J1YJU2oL(_J#wISANarmWvcj*K zvE!TzF3ILHLCM`WB*fs7$j84vTv95zbZ|wzWudg;l4g*dP~kxq)^Hk~-DS!2rI<&7 zfNI#fF{YTqQtu+A%8EI0L+W+$4#cWAbV?0$fhq72aTjt4^ngfc{t7AQ#5>|S^W^y} z5%r0Ux;zzy%+zsiL>k^*;2dlxilueLOs9rwFP?#YrDtHK{!mErpMJUJ9Y1_6coB@gFDX+Y+Y{HjmGq?Dsk);MEyk7W_l z2K|I}0bw278Nkpd+Yl;(kxP*ZKs7K+RwN*2=m^9Nk{JTnD~;M(4xV!X<@{KSvP_z) z>`0x~*QQ{|w#L!dgU7hiS#a7mdgsaDwC#%1esUO}RV(CUw8<)bgbR~*`(-L4d`C%D zIMqodQq_cIqV(3Pyd9{QfNP`9&+AYEmY%8HCL~cUG+5oY>&6Lf!cs)J|rAzr$ivRkc_wSaLhbLEUJFjHhXiJOQ7*Zk_N1`x{Fc!WvOglrV57 z!0@K3oa80*pc3$6B^Y$DKBUNqO-q#U-3DApof?}K=e~q8TVvCbT|g`l*TZ&rpmzbQn zn(k16fWJ>ycV_tZmFgS2z{{^z-?UTix#}BUvSWk-BRfkQuasM)9k=+eyw_HJfXqGd zz(Uq?{th*ZpH<&sJ>qoLcU)Bp)>PkNIZ9EA?-6}cK?Nrp!+G$G@r_{Y?GY`i&1C(b>F?N$Tk+*CMYr)AY7t zme#9p7q~Q;Twy|77*)ob1o?ZeR@)`&0N`K<}lo``HuXYEBFGvD~$1JZ>{+w zY?jg6FF3DREBZaEey0Qgm3>I7aExaI`kEp$1&DdnVkusx!TX0pX7esjL#HZTE!(#k zUL$tVz;;KPo(d)-UK6;^%FO{Fr?xq@=Ue24zeba8_#FCcY3PWby^c@s^e4)3;HCg3 zN1GcC`|;t0U@-G#F6eS0|MJ!N1;^$A=~2X2s=_GvWw#YZ$;r7@+1Ts~uWm4VJeWP| z!t~(x6b4~fJ-Zis*}K3}^rXJ<7crKWq9?)4oiJ^*Ts=-`Rng6l=PE8esd`bxW&Pf@ zsN%vKh?ib=`2hcTvH4x%ins8KnoYO4^KtIbiptIOs5R3IYMp)cShGK>b{PkStDcdo zyfn*2{PV8z($pM42#yx6in|a<4QDyWC(E6~U#3+raw#33jZ;m*qUkzF&5|8OY35B= zL2If))BIGvr#6?OHj>+4;qy5@k)G55Be*`8P9i?rkhMSto3D4@2Co8APckvhP@^bIqL>Qpb{_!u4%4m4HlDxxHekdIiZx*Gw82c?Te zfZ+jsj3RJ2Cp}?Rpj`3il1e=D^nFI(xGtyb5?56QV&hP72%@HZJ5YVw;M;WmCTQJ4 zwJN>D0?)NjzE9v1fZ0oF67;qF^P*mScwA(nf-&4v2XlwyG0#4Y;h{T@ekKgv#kIdE zKF#;rK69GCSEsuhe?#}C=lraJ~<@PmI@H&B6%$aV6aA!ycR1HDzGZo-(exClA!^46kl=Y zTqLg*s$X~TNkuTKQ`dqUhpx|nld2i@>&Q6Qo%cx^#&na`exvU&E3iWr)b;b6qO8tP z!&1}_HSACf05xn7pHRb?JI@JEwTsjwGa3;}bEO-iH-$Yc2Sp50%G-%kV5Auge?uKq z&og|(2uLzoPf#&BeG}mle@WkzXoL}wzKND(oQPO3Vh}$~t+8n!%6x>jVQQ^u8~$F? zHvGM&ZTLGVnzapmPX*;%QIr|LfFbo7qf~VlbDvC;rRqM6G1K5_$6H$(C*1G0Vbg2P zO5DO7kY`?V2VJr_hnGX<7UyhFK$plpKSa-=<3QN%=fT>Y=$Vj7enxP*4?d`#X@f@5 zdH~s011ayZWbJ3W-s3*?{QH#)!Yi*fEGg(BFDo~f6#Swgs!%43L|2coj<|M=vktQu z=a~@{1tIb4451a`%o#*y_*}t=c=7}wc?_%@D>E)&&LCj&METY88EPVN-aXm)c$7kO z;b*sCCR0hMTPD2Eycan*h;}LA91S5Usp$8|jpm8*e|lsvKO@MYAyd>y*Hx!Q`4yHJ zcC4RBE!T%f!MBrCRZ<{^k2Xrr3c_%4{?bdi{xfR@n>hcF&h*BTH9oho-{wECd+QX4 zk48mP`gC7o9*o`85NuW24Tz$!P!!AxVxMN?jQnLMQK!uqwaTZB z$6zfelmRcSZ9bXKuXtg%2cAGS0T)C#R*PG4u6Q*;V0r{V+|b_-$|9@%7*OU;oh;Ui#Xv{8@3l zDB>wgcu(1{yVAT~uTHB&IvE~xnkvovXIGk!H7^D))>cF+8jznu*2F)ijny6NgqN)S zDVXgNetg=!(-abU^`4MW8?%rp57U}+6hA5d!J)3C59 zv#^B53}`6J^)g#ECyPeKx!ekz%Vl^KPfiQU9kiX}P1T~{M>K%+qj(!Y_Rmt41~}_b zcYGHwurxj#gVH0xKzZ2I#r1qTDl*hr4t$qVre6^s>R6y1HG5@fV7oON3}AP}o(lC( zO4``zp_EbqLDZ{Gqf+MdXvu~r2S_Y9{lTu7A)vh5-?Nzqcw_O9Z@`Pjq=P->rGH;D9~`dUf01DqeilD5cQgRXz_$i3q}q1eyGz(rV?=WEYB0E! z;6TGPn8x@cvc$E{b9p2ZgL`okOCvp?QRV?g1!8d%D^+{FFICH`A0rmy6c-eh@pY@= z@)pIAkdpv5KdnTHvVcX;YVQ_jMGgMQPu{}5vpmyHvpypw_q+mw`5lvur;d7knn`j0 z*7TI79PFE?%HLmPeGsmL>oZ8S*e~qHU=h$bi<{VM{9)o1NYG1PMZ&)?@N}>D4br_H zFi_Vu0u^Ny%wB3Hn5{R-Cgt}2H7}D@P4m*=u~+zec5L*m)#mZ$M`A%exe3zceR?@Y z?qGkV+r001^EngS(}o+5)Zy|REkEg>S8x$PV^Wan4?Kwz;S3X%CMl$r)@b|JMu+88 z?uzHaO0w|3ct4Bxyjo;IIU|NQ?^2mulX>Xm%$2T!f6)b2miU*|a#W9Cj3oP{M%4_b zczO(jc{xVML&VZVNW_{eS}=|Ae-bXpAqgX5QU!YrEsVMnMhCkMAJ8pHB<2nY>RfE) z1Mz5lG_p!_hxLi;4o(V{^z`6A*RuHDe->=p=+EHvD-DFN01o5El<<~KRk6US!G9S} z16uk>Xh5PiHrl9=H6U|n1g@Vz?k4BMI7-Z)7InydqjkcILC?@k)w9BT^z6G1*|;G& zz*%f6+oW#fj-|KjQa2uA>c%6VlXAd`>h5Lm9dx0*4c*H{w|V>eXyj-#f(kbe_{=1H z6)4O(4T(birJ#CM@46{tmu1CeSsAz(Zrs_Z-4Sls51F5lL3fw1Bs)rtbKxjmg2#`Q zyT*+MYZ)(hz4U6UdBdmLDtEm+m5W?U&re0Jc_ZAPGtzTUaL@dBUn z+Z;H<7HAFkWp9x#f1V|5zy$IeJbim(rClCk_laBmLww=9zOBuTUE7SeE*dkIM@w36 z`p#1A&W7*Q5Fs!7x*{l#Oy;CV*8G(BE?44yxUi|cNuoc4I`%ElPbuRZ~-yJ$Jj0RP;*YH z>SshPN1H3n`A!-G#gjdT`q(ud7gGjzFt#b=Jo+`dLo9fITsM`?RL$lCbKSBr=Nhzd zU3T>+f~C|~|>*I3w5m1a)A6{TrMMm&w|Hm(gxxu`$QT{3?+ArH>-EMS$X zMDu2gVhM;j4>(tgf(?l`Bq}Cy)S0_c8xPs)5U3gy(KNw=svQ)VsI#Ephl@gjwIT(D z^Hp(O#UIqUD-C!jV!&rqHY%|qv5oR&(Qo-Ol@~*&7eN55W3|Zy zBczxI86nhakkAu@)D~PO)SA1I*QMiRguKU?N^zs6c5*d_;DQR|bVH#K)(O*C0`0N& zhPbrQI1$It>y?HUd7;SlZq-sWBE-V6pAk#a=wfo8j}jL6S^`lq6730o zsRgGR$G7G#_(tRAmn@O-&3Gq#3&Pj(3e@uRd%Y6tl1qQIUP1lcHoOA#L>k)Lu@l#D z7fr@BA4QwBiefvinpX?68&F`zY}SXtft3ka{1ChkS5-#Oo21aSRAOdB43ZQuxUYDW z9CW5-o$f`1Mmw66fdD4)7u-!Yqw(oE;^8l84S3(0fktvT6_nX*Nl1n8|GaP>Y2s{n zUPVG7ZwO5uW_%EUd1;$+D!FT z+SBH#Cv>I7t&Y-Y*3!3^JM&P`lYBGRfB~uZi-_+J6e@?Jpp>Nrld-he1hF!|e-RAS z=q$)0dB$B_L}fn zv(@$cv_eUwB48Hczy2ky2Q|q<^qc{U?6m;a^&R>}4v7HiY`!@?m*NaNMA{xnzVmjYP?-lIBgM`GHyEM<<%= z@?Qb}YaAAVdy1oOht1IQnUeFb0CvG03%v(h3cXD+VXM?=jie>DnjPPr)0;+*u;VgEc;GVCj z07k_nLSls20k?Cq87-W4g4|2ylVloqvx=etON_{OOsqhXB|^o`R}HZ@TDW*Rsy#9q z!I-E49RwqZn)sMTqy6NPVLPQxmMoGh;v&``AVz(vNuwl()asbzVg8mpYi37brasjO z$+MQI896UK8AS-ne8U7!KZ%*^M&bukP$J0E=LokeJtym>%))vOXooUsNgV=89Vrg-y!a1&KF2<_ekqY2H+3b? zM|Y66Yg_EfJ7H@?Y45&UNDywf9Xjn>r^g(a?U@o*Yt;M*)NDBgd{#}-2-Vl?H-MdI zzk$0-egiWOJOtAtC>&2xR8>$h@! zm7Vn0bNvR_ch{8}l$;6wlIlU~k_-WrOxJ<7F47@+DbZySc4ZP_SAC$c2t%}Kv89u* zw@ZeIxR{GpQvbid}f z=*A00{RI=ZUMQG+?FCj0*1IAvzF2NJ?4jQksW@VzmjM(V=OuGwf3M)znF%8>63B58 zRvzFr1`4mP-8ttwm?-%fxf<5-37>7pLP%}Gj7>1Qf!D+J2P4mxsW^nhXlC}0`;dfv z4%a%LG|c_YPLDGN91J$(5Ni*G19hLTqfgs)B%SS1jTtAxs;&s5hjfMOY1Oh&++VXA zK0@;sftyS+2KXq!5?O{{;OhcoM19ANlb2?Ht8sYcNS`?CLw(f7{1EEP z==TUI{=c(wh4bLUeMv~-i8mL&*uTB8MI0@^O%St>1<0$9_Q6i7Y~9T7DxF192Gz_u zC=jyIPstbHmp+l90S4-mQZCf=K~>aBSu@zSF43$RqEM0H8z zl5m5Ltf-CNjjXnKan%;?ngC=vJEj6vT8#?O`d#sD0X3kkI$kpEx80i6G8w=uf&or~ zfER$>v}k!~k=x$b{RJK#hpxT_gcW;0ju9(N;02xJgeN5g-6g&HNK&lJT_K2q^NNu_#xg-5MxS|su^*cms|1cRe zjKof6`h3=)$Nv(uW@(}`0uA`C$GsbB1)Op(@z~u4-;}x|L|SY18BNVNdp=Dn&Zlsr zVk)%bJEI2D;1(fhM=5~Sa(`|{FuN}i;F8IioK^@?t&`^3mu@P7k5Iw3UQRka@-qrag!(!Obv4s3y zIwlJjl$ZX-hf6}_a1s%NxO*DPO{FR&YScW^{>kA2$W}7h{QC_to$!1Rn_lYA9&fGo zIa5H}AzH{S7^HY{vwRc~5v}f9s>5aIjLJ~`Gm#A4 z&v6XB3OJ89Um(R%QgWkb@+>!au)|3t!q}e3SR|Nw-t3L_ywP*d<~Ff<$(Hi^yym`d z9`!ATaml`k`t*DX2>goeF*Rg-D&hE=P!Y>1(TP5c(AY;El0*Y+&Ca7kbMa=m%3XjX zP{ZLL>f_6rMPN0I|}2l-h(QD&F~6YWu9)2Kz_6vkekn zl6PX;eP_ixSKUGI&PTm;-Ryck^#%riD&UbrDwfR4^=8S7rcTWI!6o znE(MOn>(o(sbj=Ph(4g-x#f5ym}sKyXo7t$*WzX&e&nE`zHevz%Vj7ST#WkA& z)&%AW%Q5pTGGh?)RKVUNR#8#u@rwr#s$oayHq zf+`Z@OuUWVd@)t%Pn^=OW3YFKG4m)4Rb;%XYft3NT8qh2KFmy3SyX#6S?dr1>l%|~ z+CrmCFmP0zLLZ7E;|?Sc1_<{dG&ONa&dc!4dDRqn zFzo4=Sx)Uz`IXFyA#`(_%VEXdi2*B4YJh5liVwn!Z)IGshZ(CS`3J&xmKd{{=pyjS zjQJjzrwDSPSWIMIv1G`?yqGLt@!~Wz^J2$S5E{z7QTs4wvG3XqE}mtzVq6rdzRLO?K10 z!+UHRO6!mYh3+-t-TKM=JM-<(O=m(8o=J+Zbu{yBOTDZFx5T&ooB6gCgYp9;ASXSW6Ey$N7orrCNy*VQOIA!*YGqm2gK zFugdLZ(C_Vwj;+#*6VAv%(vZYR(iFoN{maQ4f#aaZ`Q{Uw)LM;M+kETcmQByNxO(khClT_&reAU4MNrOW4-xqKp z`htZXSEwr?ePUQtsx@+=C8pXq*u;3lUunp4tezy-KE%M=GURwTiGf05#EDJueuBhg zG2%S{m>Y z;Zucs(i6i&eW|#^DUWEojL*%W8`USmT8&L*Zwa?!A`5zZpAt?6j3u0rrY7O+f~*hf zbq$FPwRuRFvZ*p`rGRy;(R+MGO2%iW6cX6TaiPY5o=rUMLhv-5kRqshouEADiUsin zv%4FH)Krz~kizIhV&hu$WD3dt0j0Sc7@ZsQz*zR-As_j!VOkTEz?V<&5DbDC62iJe z7>UzecNNz5Rt)X3#}zfQo4h79yD1Cno`@q$#9|0AB(VPj9)Fzz`;Y|os0N(nx7eBZ zsSPVr+IgUz<@Ym)Q=us-B8lDaEx$e5;lTD3aOwg)_7047ImL+?PNcO+-}QIX=2{vG z;I8bkr;>zU(|}Uqp2T4`%aoRg6HqW?wjN#L*4n*35F@K+KB{Qpnje_2MIGJamaz^^y; zS5V-m;lGIjANB~hw6H$}S^jkq_zAE#W$ExufsYe)meiIvMc|*QF`zFdo^~d9+Fu`m zf6H4S@U5jS1MMvE@2>>@a$@)U75JE6N#IjS3pF?#1LzpoQ4;vL+GN8c@F)Im4_Njz z$I&e9@HBG{1}C?c{>BkHNNk93DUaF1L(J(w8h&8Mh-Z*3F5Ow$Hj@waI}C-|w+CBn zy2rOb$gz5!n?<83g`YXhS~)7ngCsanyK!fKT1NdWR%}@-= zur`Hl@tD;>rI#a|lHmxP?iqtzsC|od*x`SdkCul19mzS(Qh``nal5wr$KtZzFWx}N zdSYC*19T7Y=FVuN^jFS zFj>_qw!4stJ+X7P>2^Hi;6`En(rA-BIQq=HJ_SUM1@@A2xN;_}R}P>_kDiQA{8gV@ z2kc5whXG7SW~oMungi!=rdA2DWd(oXFCzS%GIH|bBs4pIr^M`e5AjOrz4l>HmY8Aaa9REo&j8Rg%SGm1@IDd4%mKyozpd4`|? zY{UR6-LyAyMyVq^qrhpmo=rH4@Z(;x`Mh3h@@og?ih$sHKoIb!Ac9=#godjZCr4m$ zV>r-crxea8AhfG9if9Xc^~x?A{cuLf3sscQDA#-@!U=L64YC)iDF5IzKPfls2zOzA zO~q^6MnBq!EcV`nHj?|PH`WH-nRSYn0z6bNpyObKtX^OmqF=3&%^ReDFbVr8RhNygAhCE3j zEmd4hAW2>>xwb6+Q#;zrA*>M=v#!iui;ANwySZ>;DcG4JPM3@}*BV0J`S*08Q~*WN#NnOu5OO zof`Q7Yph%rwokEg!nB2AEeVE*$;OGT3wJE?-;aKpJOs&5IJ4MkeXIdr-O7C;fTm!; zB8WcHSWFm|aP+hCpwiEj9MjK6r*pMIJyF*HB>$82KNmyXCjDpjl>UdZ^grtkLi#^$ zd@WbG1q{!Qr2iwR1tI-cgB5kIWrj%qcFPhe>m^{9!b97{e&kU*84F)M(9+iElsn+x zEcT~F5lPBYIJgq~U$RO<5<~P1&gD+3+<_$ar<8pVxdVPACtxASNk^zP`Nc}?pGm7* ziG8;b&cZ2a0F%YO@fMc2UF=Uvyy{Eji(%I!x^f46Ol$-FsU3+|HDT?acZh2Vw+a>?Fq=#a|gg*t&y<2tF$W!B1a#x1OR2^gHg;lcy<5KwPs8vueVxSYWcDl ziY%#$*=MD_T&^wS{YgA72WGTt;t>-gvNA0=c8JGlj+sl{LN*2i2q6P=*(Lz3w6NM1 zgm4tXEEa$cH6Xjib}Rs|umF5p5`geYod45V08(`Ts+MaTUNI8_5YM)QQ#y~(dJcA* zLt^6N4vE3nr=h%V=sLv8(02e+Y6YQVkNZ*$D)%OOSrSwvbWi|3kcEy&VSlq52_2u6 z7(!>TL+HG%CUn^C`C}o9kQq#)Lar*eA<=FmHrRYrVgt(E1i8cXxtmkUs@mOR>%f?1r-_TAZhVdf9(He$~ z-_)R3BIj64w<;^vzk5JfJhfd#I`s%S7aOJpZhuWuOwbSBvq87H!{^idH`4qQK_-WY z^N>5Tk||}PjX?4iNkoP2KkqMT$E&iGELJbhlCh%Sm7+`ukz^DCyj6M4Y zonNK06AM))YVrd`BI!zS^`L9`g{O;xYGo1y)v7egK10YD{!FzN=f~DU+t3=Kl`6)V zRx>&61Tg;3o+9LoJF9E1qj4M2hSUyxFXN`f2%=!el#b>p&6X|MlwD|G3X=;GA@#R5 z;-{dFW<>;RY19Ud{3sMZk&|=wV6(0465pRwa*lnSy5DJ#oYtU=;B82|DKLd(Nnr|0 zmu|32TsN5Sj%P^{Nm!Mh9VJU61h=N8irtznneII(a&<~XQHeM~he@&s3&j&&(_j+k1Ruq}gT!*pCHYc# zV0TX&i+?4)Cj#&{uvozv&bptZbO(=G<(5cln&Y&BM?Eqv8)URVt6m^g13~fDnF;42 zi}#8NSzz5@S4yfCkp;Vw2EH>3Y{a{4a`a<_D-0(O0b)T+~(~_=`+G(yOfriC!Mb{Hg`yK6API+D-0vM#WVp{DZQ)R^>fCf;CX#fR{ zdJp0je!=@zIw&iD}= zR|HQ6UcG@{QWd*smQVVZ2RK|pc}in$lA7u?%Xy1BLZJ%2t{d=8Ml%;$)fsC(#Kz`CgRj`G~C1uV`@g%d zHHE-OtGqtOXKuv!7}U`weEj#67y#8%RkcVPh1ycu~s zP+1a|zVO<8?4-3_gWAC2=ACAH@1))J1#F&XQqJ-fC4<;)wU2hI8^!_3r1#Li(oH5X zkD*9T+(Ww;jBrSh!kMjHH=eBAuG!)yx0uz%?kH&6og3Q+wyB;kb064jXp*x@le~<5 zV95iw!LX_jE(6j!ZUhLxYFicavm;GX9TCFab064xt;w%xjwjUUx@UKSCU@BfR(A;| zO|rHR%!~z+vqpIu6bUZ8Xd}4V2R2(CmM^zk{?6Y=^*X$BAJ}1`>g=|kWeOqZl?@`z zf+Q41XxYwAogwU{Xck zl6564ZML=eScEOS(Qaf5kVk2_62eKRkPt>phVyCEb6&^Sv=8jEB8GP4?YdlENeGMVpFDLT8OlIAym^FE^;?2|_PRyF1f^OIY zvy}SG%=+HMtd|m}sxj+o&+cB#x?8WXu;|8vS)ca8ms=DOmHsqh)~`(Aj7!Wq7}}Py zA)|+k?R#{S3VV?OWj6f{h9Y@!Q3F8B%--3{+@rf$Yw|_S&TM+q zvr-~Kl@>|Zw&5^24&P)>dS*NB|wJTLr=5g}Q9wMC&t(q{wNNu)v_E7fD z_Vl~GvooVdP#&%=36t~o@~4wBj(hfybZs&Og)OLxU2Y`zEQ=}ktX}EXUeOl8Lkd&b zJ=nEhrE3hM4U(#XF}#vT%9lY~3}h_tTUnzwgWgR4DoJ(7vV1 z+clea-l7+J=dFso%I&w?&Re~Y`zUY5c@uZuj>(nE6Z_gL?l^g14^M0R@6~AYt$7=+Bu}?yAvrt*hp`Pp8f;ie zu9mSw@ZR_^DHLXhLZm%RCGgE0v&-`-V??Qg5{cwsn(K$JG1*Zjk9A<5Mf2CDBH_V~ zlEl>aEu1|IQcI>uJ=#7J%>1#DfIJ$BqoUiN<+rhC8M{X<8INR_p%w!ELK=A%@Xs=O zjr@W}uI1E|^qh?{Ag2V9dMtJ?d5_gP@;07#Um@?mVhkYJXlD(ahjc#=W8d(u{GX!}T_gw@~;=zL-iZ;>Z$d-jc-zd5!uR@!d6l-TJ< z^KQ)@5~3y?6acChwR4k`{b;jy6mvJG03M*qLf}gl0;2GhMB)1u0m_M-CZ|W7R|2QX zf5`S(a^$(=hWpQfA4UClR3)yAfJ4YQziAGAtCBc>5VrRCE{6pj$ z5wJRCvmExtXDx!*e@I8NET_ZiPTG0eYbmK?8KT`M^uvALCrxAQH3WL9G8nov!jj9PqJ?} zVt7s~Hel3_9qY>pYF-b(bbqz9%K{L#kpQNDAtWaS?yMxN*kk)QgS2)q8u77NGYTgDk(Q$7>o?=#5V#CCAMDnJ0MDnJhq9e(?&fx^rM-?5t zA0m4l7*^IlzM&&_SlEjiNa&x!QjX!Oc4ep|B6;3g=$4^v9#POe@~auP>T2gEU-WTj zYLqi>oR6Cl%#<07{nZ`4IN9r9jhsM(bHi$pyh*z<#5BAsqg(#=Ppys0;npfTy57$8 zwx1b>B6&)9%#l3j!@~aXE)YuaOrw_f&`Dn~kx8X+F-l?RIf|FY;3yuv2C7Y2T5<)X zA8#;D>?4L}S3s`i2pg%@a%>a8NhWPc@+j2w8e(`l6%g#cR4qrC-niBKUQJ+Qe+6^x zTV(QJ$5_GK)c4-T?T((E5feS5Dd#y)+_GtYGNyU(!cnq`BI9JEhOo~k8rTrJCbw{B zZl<(j%y`f#Nsz6uesUGvlyyS#TTV6c?upsbO;t%IY;=(Q8h5MY!Ak$wDPS2id6FJH ztPo;#!b6VZ5r7sR%Sx4C$0A~5;;wN#GwOz#fV|u!wYZ<>HET1 z->N~NBo&uX_i#AwTF}@}Mz3LZd&R}iyU%1r>R2*DirfNX=Q%GhW%NEJE*?Ue!K_t- z!Sy)P8sBvgEV~xZlb#dF7dk_ATC_Xj(*Ek>*~sgo+uY$32}94Rs~VS{3NEc(M6Q_b zT?f-*Umb~njIsd@i@>wBRv+^;w3cVn6g=AOB6d5zlfX#>X>3vue0UphnShjL+$(l; zupO=IT?ck1U=55=&{z#>D9-QUvR;@{Gx5c{4!oEZgQd$VSBPdVW7k1Z?K;qV&gWdM z0pgJa-c^CYyAHO2kF#gRPqHg15vdx=b=;ClRP8#*?oRCQTTv%b!WFO%BC4 z?MZS+M**c!%;=R-D5hY&bkcxBG2LLAqrXFB!{k~NNHf7}HjYn>#OgH68)CLQLoqpo zk_DPWF+SWa-cRG3{QiVcj2LEB1QqcD5b^irW#{va!Kmm+>gkjic69rJGrEpXlZvv{qFn%J3VP>saA}Dk`L|VD(A(;V@ zWVB5!OjFrgEd1Lu zDwgsMNJL!fq8JK75_YMcyb4g=tb|Mu9>$CfwkhzlDnmXw1_L_Ns5DsDX>nr_bwQHX zVldt*Cc#AzmiP++nq2(U+HE6gw%bK!_|I~2mqEkWiV^LFH)G?uLJVU#KZTg`{o%S zy45$e5(PNsBrluW959}%M&miOZ9E)cD`8lB8Fe|o%+zL(yNK(`HFt6 zYo!*L^KgXPm`?D#O0hHB4b3*9HOj-QRD%?)krpD;42c{0mt{&_FI2>?t>6hF8XNGmwM+_Xc}QbOc?N;?FQ34di@~9PkVM ze){sfB|5_{H~AE`@`SwD5ecc@WN!&#UwO}!%-?qY#Q~A%^tPYhByUM27C8H2hqq); zX+I(3c@J+%!%{gCB);h_8Q<`>Tbu??JMxz3h{cSsPb3;R7hC~Om0TRkc>XKrEtwq8 zw>m9RG79Az9+&WzSpIU}VI?yjv&;~2pH0NQPl+LUmmDK}l!%%N#|X-H&07+M$i4Zi zT&?x{NY(G^Sid7riCqLJ1(j)^Id}p26Zx9x?`G%9=uC_i_ZJ+T!y)AO#@@oiob6wh+828eqScozkR-Ml3Da&~x0 zreCX<#2%|Hj?S)oNnUA%RY*Gn`APH2D$nGo=uFwM93|rDFyF;AiO`)OF9k>23XbB)<@8JDl(ZKU%SFu%Ld@I( zry)}!V0*CLZ8W=aDyF_o7maDuM%CM$o+lL1Wv0Vv-mHr5x)@9P9kmt+jQxy1#12E3&ywTThY6bEI`uWgK4 zMAXnw3$~PW%(&NE5o%!bqG6*?n}SL$A{r12AWe#k8nNZ7JTSP+d@1&hr?{xkDZGTz zs!b)m_a@M!uqV9jE_$ALJgAsp_(m&7rO&Y=LNp%Q6mo96r7AoyPi!HJnpH^zGNcRiivyEhVuWee}9KWOsHj$|+#@=<*uAt-h?*ea83_+noI@HGg7KdR9#%#B8Xbt4wR^iLz zs4*`rAk{B})j7(x;YIrc-diZ1Pe`$mR|jOVvom{jSq&YHVInYY$hnI*ZX#|#1mxKz zskZKJlI14cxWEm@z1|wxZLKhqF67>+#|3`KBVqjDB><+A3zfpzZDq?XU6WDO4&-SI zd4S@qh7RU5aIqesEtDr4~kyB4n7q<4M2#MPk1HJ!BUMyO4xzvNPt%y#FLNRkz(A( z5*%%|kC!k1*7Lv6{ZPM>&uzM0*><2iZUj9)ReN5n#T)oIV5R;%cR9~}5iCQUEI@nN z|3)}w?2I5?7)UAt%oNH8)!lA|N$k5JcSDLoA{8T|vcZ#g35QqOgD;8UQVxs(@10d; z{pwd!Nd{3yi*g}s0M(9>Hsex*k}|GHg5YpP5@e8SbVxF3I$owXYn*<#;J-H=b2;o7Jx zCkg$7IJhgq=EZXf3n3I9qm)s?#B;(#v@p{ZRi(vS zrQVFonLT8RUA|7-k8%WgOqAgGV+Jyu`at3Hase`>H=+Wf=HhHDv0^YqoMW2;1P@8M z)ufVpVx*EA-SJ^EA!QDbMrO-u8ZL|P2f45Fx3lQ1Vrc0pUKtmP5kr&Pk)n)Xa_!_n zSBHQN1GH=vJXYxsXA|*etxDlBGqq`NHwA=fQE5n~2g<%iAC&r&_YC%>lMB*KYX0da zupf|9P=kisA6fxK+6o$pp{sEnCX^0xIyyFI3nwUCnxPQ^+*8GTp{r($FxA#teHjDC zjMM_LcNkl*_St2cb>H~6ScAwt6+{+yfk*`kMyqzIhT#p!u^Wdlt-z3O7EwEx`Dex7 z=`zFmp$#e9qnp*?t!A>315`0-rnXSL(j0kNx0=Ch^Lpu|0cpW0$B!zzQKrnrgrIB- zTYnj8vtX~(Rs7jfS0PiWt9Z2wSV8aIaG?pgdm~Mi*V6g+wSnqo!}MaF1>^ok8n?-U z?-w<8Rs$yHY<4>(cUM(KxhaJFgIZzMUYl!@s%oxmRkgud?^b&Q{rlLssye8(B`LwU zVAl|O>Z(#wy=lSP_kY(rIgcWKUFCH=N}Qz)ldqLn`{VYg7E`qj;w zdHVJSdC`&7SN^=%{Eik^a*K55lorMnErM~uU;H<@bMqZ+r<~KrlEYYQi|}GozEm)g z-ZsY<0L@0aU)G9u*JqglG2L&)hI~X$@wQ!s<%WW9uk@&)iMuAnpLiN ziDqSy0z=GrY1Rprr)0s%LQ(oZS|XcK%Ne=9d*#DQ7EI?g;2(gA>*wimMs(8M_Olo( zvciTklcuN=vqFN2lNTDAXNnT4s&MvG0hx)(f=0rY)Y+^8=dMz06q}&0YW|_ymdy`Q zp8f3r0x?hBk$BxA!9>?Af2DV_PIzZcctg0PXyXfjs;LL-kF4}>FaDvlCy?EB-)=k} z+7()rwJSCox&j*C8BJ#Dm0RR0xd)??Swyu%l^?5MCSBrClU^9rg(d6n0Ix~T4HSGf`|8~iP&#h9%%>b2rJNr0;U8K4N; zPE1|;7b7`N2`WA#5bCw!QjyZAbLCVtR7hT*SSv2d*acQr3{^^_7kRCQ>ra8}!t}L7 zKA`%)kzG87+2b{?kpph3Wi`)H^K-QppD@Eyo97bsbYXFk4X142ArjZ*WBsI&BXpp$ z>^v)K=8NWbdZG8d6`h@RKf&!D7rw4?1E`;E+6MrxvlzG^R5YLKswV}RQHES8A#k`J zgT8|ASL+^JD|05Jaosl{gdQDmJnMnWGYh|Li!+Tfc4n0sm>dQxj3+w`zLZ9>l0chm zLprI_nC*l(62@KBc-m?$}$xinWCf zorA4*9EMyL!~PM!`KjU6>fPE)9`OwUNRgW}c!2K_&hjv$Y+C0LQ^=F4Jq<=npOGea z1;{!pEFMyw{b})oci!4u(-jY>`2(dg;SX=0jU$Rh>r)fB%(o4Xn!y#rZkkbT0(&YI@lN9-iGH&Hk zjau$aylp86kj=B{c$+$H?BH$D6c}=i)NwY}*eI3Olh0LV%#0)EpXYYV4lDOM4GmIz zr>>A1N8D&}=N%@7htkh?_dBFsyFS41IvZJ?;o!~?w&`daj&Kl0UxT^Y;Y5M1JrKi` ztf@gID!EC>pPthAM1tGx?p;QtvIa&kqZ!A*7|jlSfQp>l$M86(>vgwNx>Hvd;{Oft zQ8PYh`vb-Kzy~8uUYSHz(1uNinY=>FwH3NQvB>4bB3a?kC;nA&%AVm)c@SjjH9MdH zF@>>(JN+Omqn*wr0-(_Y3wK3$Xs%V+(5U`-ZP^WXi|T*cWRP2FytyScmybD0&5;+~ z9A2Uw;C{(xQ03SiA%=AjmV1Q?DjZ9+R20Kwj1DN}qN4#&8l6o`fU7AH9BiyH=Od{W zYf!u=L2*$~#Qoy6FaN2DmjioHwB}Pq(0|Rn$|6#k)Z+HWs#dkQJ!+h?R%a3Kw>B^8 zt`T@1Zt)V|Os~MhrBcxuI1bPyROL~S-yz9N1fx5hS<2dV4xJJMZOK`00}%VmO-k`;BVRdmf-8yx07ym zdP97Q4y9tHgu)@G<*^o|cw?GP+7TXXZX)NQ6QegYiJ5`JX@GZURCC-SM8{+xEX3X= zxLFKg1Z6QyPdFXN*tY3O+{0cn6$ubeyIbltZC9=%D4~%YSvA)UqRm?Fu@?HKXMz67 zny7{_1v`Rvn(`rO88A4+!tM~LM3s$Hkr(7n4#aKX&>)mgSGksW@mE2a_tY2TJzk8* zt%9QI$0K!R{&AG!v;KLD)z5a?D@<9dzopfW4K2JX9Tq%7_jNr~(qZ^0mx#4}1QZ@j zGz{A^&}+b0XQrDeU$U^O8`AXMQZQDa^ygUJwqg*p;i%hTQRF0b-nIH)es0WSp|EOL z0Hlwn-75E`;Mmg0S4#6Xb)u0vj2_L-2-I5&Z{jkj5z31YilrUk+7!5CDYBpv)vwuQ zKvGF|8Mv$DGH8U$fLkEZMxzRse2wKAad39lm}qwvh;O&*c7N8UvkC4<+ax=mJQCUM z6YYFZCj~4nFsvLgc{btC1p{PnJ0CeT!OnNg;(V>iXBxQ_(Rt4fk{j9iv;k}YdmMBT zjt5auErPP$&WH1vO9DB4T5)(T+4<5pJF>qT;9)G`C*Z`3eNuJ4>CSv7Z@6 z-Og{IxF$QF;VE2MxASe3KqnLJ{MfUy7}?LMlaYn5B8I5RjJ#IEJw0_p%ti_eQ%n}C z3k0PQ3mEK)O92>St2;6Rr?c&j_%bzf_iCT~^M;)5YoYR)Jp8mAApB-GBuSeD!~av(>8+B>5`JNk8kdh}~A>mKd|Min!+qArQxlK^38dnp!= z1M+<<7T}c@XqAvcQYRSj3$&o6-_Z4(+14NMAOWYON}Nk{yQeCFNFJ#Y-I^-F)|+<- z;@j1Tt8DFqCOC6&N*P^@;VNCO7uIS_z0T#>-86aC=&t}e9G z?Nt*}#`;M@N{GK-Aw?r~A$1`ODYB#~INB`F)|TM0nvgncp8N&~sZkB;Rd*Fa>QOiy zy{~YKsjQBK)R(pisTHHcTP&o`)R5te2^r29Ag@_SE!Ud7zY4c|7v7N z{rDSXM~y0PUvx(yqCP3(w%p_nEApe274=`t70qlPc{A}3r%@>R%wbpWC7$73`SNn| z*@V5s)4LT|*}0c^l$2iIOT59@vMu$WN}ethAJ7)zXn(P-lAy~aS{gWCiio;GVe(YO zSzHBP$QkT3?=WsuD3DQs>#*4E#QPz(3BOmnjDb}a#y1EqJ4772Ky#`aNEm>V9al@4 z+tZG7Oo$i-s%~z_8E$y6d=?i02ghWw>wFd$frqioH~fRP?@-uxip~$kSzK&6W>J%E zv!`{Xt;dJ)%#y{#R^>fkk@Xv%tuaH41&J8J-i8>%-qjGZowFZ!<$b(DgPOmg{rkG(T4cc4_w#?yQUAJiK)r2U%x3OdA579OAZ1s)W8QZR|30kVZ^(%=U}yxe8+QriN)sH&8E zZ2^~ojJK$uJwYl}FIwUwj$H04Wp3mc_ORrWueN|kIt;O6Z~kuJPFHO9FWGqJ_$fB1 zHOmvHaKHu*mx05i|5UDBIL>z0?r1YegIOFvn2{f`BO8o7_;0UVySGX83611~wwZ6S zLULQBkbJumf+VPKiN(1V@s;wvk^=G?9lD41aOlEBl0*0CNC!C<;eewa2gH$G##L@a zm9>SMJHeZ)AWJzMwKtc2xkFk6UNu*)%+ut`<*mud@PGNPT!!|>xpMm$2T~$Nxe0r! z05#DMSTF6$g${R$`tR<)Z687`%F|v-Y(@Fb*C)1u+3u-q*o1OyY)pfAD_psgb(hrh zTj0vIBl9hG<$^Yr=Yx@jc32jg7}6lfHVbq`8dAJ!6cpawlUpcH%A@;Vw*#Mu?WOrNhm40%bvZf8VCZ>C>Y#|`JeX9_ZZcmF-~9YJR0 zNGtDpLb7IKrH7?MI17n8C&i`w^I0T~-l#i}S8yP|IvW{ApCf9}+4f^`uR;XGe;?2l z8NaM6SaP4PqyjGKiWYcUSLJ?kRcIp%(gTsaI32i?bMiyyU96G=RL>1vC!te}^j^&^ z0t54$buQ(iLug>WqY;yU?>t23;VVa#4dMIC z9qd1@TPo?sb+d!JVMYt}t;5#Mjjy(E2LSWK7F(^_N(cB>x*c{Cy37ki?Uc6GsvJBh zlk~Mv;N%&0=H5PR%w0Jw=B^q}&Amgn?eJmqu__SlbN=;a#7*}3nu5gYS&M#&SIQZ| zB|#gUyu{=AQS$z$L`E%uReT*B6~Gq?pnR2}36!r)P^O$ut5hu)797ZzPx6s9*GCo1 zVA=KY*MuBGkpyA2>qU4%3keQB&b6e>>sjZzQiM36k1R7iLK2bDhew4zQq|Ylp5(lY z=)ZNe_(J_9{pyqTbXsV#+V^QC$xY zD@%qhsQKe!8%^&21Ho&d_=9$u#m&Y4)xN!PA2VMlTq%g>H?;Se>kGn$mZ}dA?)I9+ z+k$xw+JGP$z|`{#96am>NSjvaAsTv|DjQnOpZ8)hgxc%$O+pkPz^mnlPWz#!Ay9U% zSMx1@+PD9#qjzOHXz~AyZCCLzP5o8iBEsgz(BB4mYMe-_(^B3yM`;9MbfO~emyMHjMjfhpe*G- z1&kk$x+L8G+u^LHX}-vjswOV!+&*;Zi&8L|CjA2QV7U1-oM%t@v z1B;;%m0+*(lw3}}MJKv7h+E!!*s?kA&58`=2esl0MKb4;ol5Izr?OvVaCxV)>uI-S z?&bz$?$QALjMD!6GR3#`!%HnPv{{+dHi)x#)Sii7f*kyp*w<(j=t>+uH=fz_EJc)Mo=ef%k;Z68E-oApIHf>X8c$;i| z)y4v42~7zpz`4*0b98(bvj@$_O*jmFWxI6%XSU88hat(2uz*^kd=7 z{q^=vhS;wdV&Z|YuN^#)ceisn0VH#|&DMy^eLlF{pSCJ4_x0B8jb(E=)(E;q)UZ~% zzN{_3o+Mlj1G`neU{=H2(s{iQ{;}3(=Xgv3S%QAy4b)Rg&rJ$SnOKvPQbR7q#}PlW zZb5#kWd=P5-&qsIYaE?0Asayi)^XG#eJ)>aMIQ6R3TC)!iiH-do^kCao-(jW=IpzEq*n=wO0~`b6xvrZ zG-o6cUt*EiF)J-AW1=+%Y2JB+!kJ>QATU$%BzBNjYu*}P^VZm!OOGA> zjr`kXMi+UZg5U)4y5zz;{k~OVG<%N|&0Z7DhS3ZgjKMSfXs(b{fX5OK{BEj+wMs01 zy{acgr-$Qp+5XfCA~}9K5h0JKA}oQu-ohl@>zIQEyVT2>nI@?qf0qdnjz21SV#Qn< z;!tmJ0tUQxR1d{RI(myX@j(^gVz#0?(M3xRN9y4Jz_Lr# zv1V$uk)9R`R5-3=XD8hd6;CPIJF)Wc2rIF~#IQZw%%xFxQ}OOrnYi?}&Vx%&>W`*E z7sa?smIqg8JtO6TScGImXC|mrRUsD^i`6GX#k%?3vsS6J*oKDm^-9YE)Tk0Q`T$mS z`q)IGz{|37pANuNG4aE30A8A)wBGuAD<(_LAk^Vq$&N?Z;L%bAh^p}ey!MCE9OL!e zZb{jg`5EqoKu$dG1H7#@znO8~-q`SG3$oS)G+K-fFmPHXeXIOGE%InNx2U%^m?5Ih z4?GQ`%z$iRfc^J;%PtU_Wh)h&^2yX0uN9B!Gkolvu84`pbwwVY)fGYZsIDjlt6Y7& zNlQhL24AzP6ii+Ft|qRdt4%1lcA$rdv6*Oe))W1fHA zpEYGq_D}Vdp}wpuL%qngTtwyhCqKJJ05--q_|8ajXq69Gdw&vmH_~>r486y!(Ob68 z&xC>UAP+ZcN`AQ{jWB*Y%|{?1I=+vO^sJA|d}J{C_&GjCJK@m5qS3qswndE7<97;>RcXI2W(!AckRT z?C-CEU-xNvFOxZrvrHeK^T$`sy}(|YU)Jos&htF9q;FgUCfIR2S#Hp3qZ;r!-#XQ| z3w)c(-!$Yc+B~nWpnq}ma*Hc@uXD0XB+<3Ya_U=)@@(_eeEa$$TPK%urPcFV2uO$m zR5PbaZIeInee4?K2&JOaZb4<8qs=Qxw%{_rR%n+`llN4VJ@I$}2sb4J#fBIeyO{n@ z^0Cy$l(sU82k((%X{%B8Mb>_f~0h-M7BALldb0PPni2O3mKmexFjJlecPf8ICvJ>5i_C#{GvEELDURW3)R z6-ji?$aZVnc5Rnzr%S8SE@foWWbKZO%#6nEVVhNJ9B<7>>H6rB&}l^}# z)FV0_hF#CSYrsw}(vd>-QY=A=mkNQZnMaEo2aH?#Hj%La)e+B`f zo#1z>%9tTEoMCWhR=D4wxLxAcY)sb+Q}q|L-U8`x3O-SLfxFo6XEgIWvEQT282z7N zhcHSEG^Gm^?SQFiA~$=3#~G%3yL`^*sHr5(oTEog$2~s;30MrZove<@3E@hRJ}5NN z2pU?l_|+|B(iLgmb-cyz2V*p%a1|^QA*xMLp>iW0)D@1Vx!_QcxKH5M3+-dYKZY%@ za+6*jf(I4U82e@KbJXDn0H<*>&+H~8ZOrZsny-uW0kPK#>& z(Dabs2SeP2s?s!#>?QPrS;CB!i0jvGGWT(Q~snel8K&#tQZChUI}H~8O+OimoZ7?6-)UqAA~46=o&Kv z7$fud)Dcwt9=IAS6^rO{VR?{XKTSirjluJ2pg2LyS0(B2izNY?Fo2i6(lkpGYa>3d zH9ZG^|497KYNJ7AX<2puDuPEM1Y@Y7LE`TYH=2d)SZ~G$ZcozE z8uv#Una#AW>JkUN!q&#RAlB_`F#sq z&!|q>S?EHyBcW?8Oq1L$b}wFr*ewR{mzRWAlCagP25)_^AxeU>pdVE)F*La)lHm;z z4G*FmOwZkjmbSr;`{McnR5BTGx#Q?(?pXAHYkyIEn(w!L<}`n=PIou{hVD(rw~O!k z^lAM#y`)#R4(X?>_4(EAr*;1*pZ~n&MwU*WK7G7(+pw^jg9m8vYm%^XDhyHdZbYT# za*GC-)GWSU2g($dXh>ToFb^m-R)&AIh+BRGQAN7Vo$nc{RlI$JV?u+Xgo%Ea-ng}? zrU3fK;_?wL&p}4FHt*sSm+#S2_^)qmev~U15zV0FG^94c8H8p6oY*2Yx%9*!t38c7 zKy+;b!~4RZL(~Yo#A}U;L87XH&{kk%#GOjjt}vF_@(`cm4XL2~<$X*iIGJq$zQf(p z$4x$_XSLnl%V$>iQ9(v@qfp`8mL-0PC<0a zptNGLuiE9y@kK14QC|Hcb5ku=WAGh7@amIr$f@$`Q}a{!{=iopx`|U<%$x!p(@lvk z`F#TcRwK~3@pgKN=R~-~L#-og9Fu`9pl%2C2+&%xkIvt0IM#%OP|+`W!d{5!Ay2vT z7MM$&HX(3WBw7{CkD;3#T2(IUCJNZ7^$}7Hj<+`BqpX$Zv}(v!lu3j|ETE7=OZaWu zq=w-O!q4l09n2p%1Fl|+g zGkjDNb?ah=(pvV%3|A`~gea5YBNGH(sHvR*^jyAcZbp~y30)0v{aqMkF%oYmCv_9e zY6;e#@$OZPM3P(@I`kJNpuQv%5ZM^KDV9JT0hyX1s0L`?OEK9Llq{6{JBEMGWB#DF zXj}e_uZc7!DHrEZ-rAIk@Ou2J%ee1fDrI^#YseA_el}W!U6x>?88~?f!uoED?FLQ> z=8PBNq!|W&A^2;Bpa5MMg3~SPr zrGVcU2eU0{A*pin1%;-h$kNPEpFhIq1`p`-xMo{evsK@VEbL-hSfP~s8}v%yNw^iV z5!F_Y-6bnUAEeL9fbklHJ}ZO|u@sQng4KLF-U@2ClroFQK}|HWR!8f{TIZ#0x|OH3 z^^LCA0FJJLfDy||?gT~&69`3C41gCjU>UeIEjcfS$vaqrSB0K=oAOxhc|A$5=d$zy zr^e|Tt=aNf04SgPIk@dLOoe_cJy!(?UylYGGhGg(Gl*)Y(3yq=-_k_u2W?5#4;JS% z7x26?f-F(P2tWxLkqk~u83FrH%gtkd-2R@U&7Tl4VpRuP|GCd-0fCgI`LgN=-$jZ^IcI2 zWG_G`he_}zyYj>b#+Wl+`Z{wqnFa1nmZ6}oxpTl|Nm@aI$q(_v?#$Wn_&ARM2>wdD z32>YnF$seMreWr>^Ev-1128o|n03O=7W zl{vZBe-B1Z95K zV;~08mY^E^fGU8P(D}PVXRbuSetaHka)K<_!{;%kcT30HN)Rlc{XDYZFUjX2pr6o! zh2|mf1f)o2Ky&fRP9{f|z~m@I;L{n=qe&Ei?@f><-H+>?acv1ZPJNCP_3Y-5jF+Y) z`$#U2JNrmUbRm-`(Px~Wdi5y2&sz&tM$fM{ju-z}LnAyWH=5n36fnLMKj^5+iiCs^ z@BuRApa6N{hc1W-{XGOvS9iEpV07v>*aQMqMF`P$rX-9^b3ICb*2qH1rMz)h zJZK*Lv1sh0kS4!;gf}S~&+8`9!Zl|J-Q%iB)z59Z;y zfT@UuNm~+@d#rw7%DmG#raEDl*9S*>w ze&+b=4a&}ibCxXG#A!E@m+Cn{S@nec6)@D3KDt3Yz^!v4+88IfEohkm+o=icX-`cv zrArN^r0&miTIW%dbi&|K+5X1nuM6-^G(FHN4d09^+hbPmu)5`QW)Y-yu`*&;09ot` z9_Ees`(;xBwXBeaRu-ULlWNW=Ca@`K3gkRbQd#Sc;MSPR`X_SD&e7mjO=TsJx(^*t z1A0A*Ed=3|y(Esi_*(S6i#HCG8M|B5?vlq8ez|UWV|q~JdA2F<+_WNbMB$zLog5ub z{ekpGDaYlav&t{F^8(jWC5W`QVdIXiJI}#cy;R%*wJ&?uGI$1ux zyjBdJR-XALLH1(s+ZK6F*P$0~lZ=p%iAQ{ggoo;m^5G^XAt>)bTHub(>1IOb#PQuZ zHgfD6Ab){$!|)9;W+q3zijyfpP$yIJ3Qm`Afy&=yDj&*Zn-lcW-J+2(&@mV%R7J|Y zo1%%(GYk_Tz5X*Gm4HFM77H@CcGT9T2gJ+RB z>2PBAVAzmoQk#17Rn}DtC*06;M@eh-l%4fbnROXVE$34(nsQal^sDN63t+ulZ;}bD zbc2`|nPvRO8rFJit>gN8$^0;KTj*qJwBSpAWvhk)B;IJ~qdQ(L<)J{EI48>YM*rnQ z_wr?nKZE~?bYpJnRGOUhDJ7JF@-CfA!CK|Bl6oW~^n={VLJrLYtAnYWZC|U);|V6` zGEA1IASm_(e+ASokMj!YMdj)H`Le+ucV1rjM|_#c$CqUi;LX2u683m@i-5T zJyG2_P?&-L+s5qAbsJNk%9hKpSswVCTBTug@NXOQT_WZ>TcyNVJNPuJaCv2XXqJQc z&@Qnv{jqF*lFGvjMXGsY*gSdiRQdNlQMTB5&DYNN9T~QMfaV5F3G__wbWROhB&E1< z`5}L{siy~@Z4v}rt}2e${FHXl82ofoAwIU8(H89I<@=tJE+}IkGdO?28X7D$T#~kWXmjy@!#JfDpWYk=xCiCD|QO#6UkvJI$v&% zwew+RCu|!H%LW?IJIPG|ER>cQpTMeNPSuC`57^hpNoaKWlb@jDSud}{RPHQ#wxR2c zrTGJ3fMw0ROU|=FQz`*>Q3;TlKeSd1z5+IZ!`BzH*U*g6NPmV@Y!xS^oBzEz`*$X^D$Im3 zcyJo?1WMx5fKTe{$={@tca*PwnTs}ALM30-tch%BOJK^gP!3~xIM^c;HH@waKF}Uv?!KHuXDsU2ft;e)ENABVor_0FE?S~ z#azM4ERqb>($e_p7K0ta(fxb>T@X5%N>TIAId zdXKM`?yR#~X{AWFv~P4yFlHU_K{ZIuY@TSIXt8ukLj#l|WF5R3OZf0S8%I8YiKbPY z@+vm(82l$J6#Jwl6SdGSXQj2ul?D$X0)H&6Hu4C--?4}(*(3>IPTT|p)shPlbiJqX zVTfKRFnQ4d$YLX{xW}s%f35Qo8th|2JoeVkX!f0~loxTK0M|cRe&v}p$I8ffJKvoB z4Y7tqkxU(SSX^I>IE2=(3E@D4Vi8lYh<0bnwDZffg8~8{AUCQ}{yTB38GXf!sPho4 z*g6jZ0~+OndiQO5cqdB{IZb9M3SgHNOA!-=7ysh_N8a1VS$36mzWe38Rh_Ep(@7_( zq#Lu(F-m1jOLGTF4AH4oAM?@%OmO(jIQ}E|e(wDY(-j@M?PIOefC~^ zt!F*!S z_EGLMKe*`o;fo8-v7n$P)@9rk_6bRoxVwyJOLlh&ca`0}h`U9QUJQO$MV40qb94Uu zv7-MfXV1H)Wl<4!?2%JhPylhfJO1+maFJ(Rl!|Ti;^HD}c&P?Kpe_jnkmOM860*Kh zPK-7Up5AD~@MH6+%dkm-l!coaMM02-V}~82Ot0`J@TjMDEkJX_Z`V%!Ep)VTyK6|5 zQ?v`wZT#(tUq9uyQ0T_rK62kFzlEGP{`THew~IKP`ql;C8E$g zxrn=r7$uQ}?k+MSsE0t6+Sp$=L1gtjVPK_|QrVc+);{DNH44*AsMMg%5GOQmO~jpA zD}2CtVvWrK2{REH@yi@*TK{;k=zp*{DGAoBCTb&77y$w5<7rU9rlWWo6z~st6#u1< zVpX#W6aFwHxGL+GIzd}wNwARiv!vgZ?SUa?&9#8rj;ahZ^t~FwN}S;=8>1ewSA344 zldGY>0%#M1>9omA0R?R{Nd#ZV2aXH2e z+)4P!c9M0e>cJItfH_OF;>hDOLnV&hm(5Ef%laFkaRP^e3>?}XGwJFA^&bNc^C=t( zdHC|H*=w{hB2v=?LS$=dw*m(HyRZ}9Wp;x0f03q<^_fevZvyecGl<8*P(ncbYRT7d z<#tj11*Cly^?`a=uPpu+7aI`r7HF#dRZcV#y4GXFzjjbrpn!|ZMJ_n}23**CjSIeF zbxzTVaJ;3elRUWA1w*?^n_7?DPk(R&WQ`k+G{kRL&>ax z)Z&6Ym^&~9!WjobcP~Mv28GXwMlJP6$F0D0o%1?DP;@Df4boA$dbNWNh8D)aN06n; z^5Qc%I2b89L4Rt4`unHFfej4ahG#Aj`aqY4><^=oEs~W@4t;BsU^PN+Db>N0h_Y5w z%W&`8r9>=hibz>2!#7D+(UfsDRd;fTEP07b#>*AEcmk2rSComG$ZackK6pRzq>0#A zn^;F|8uSZGsF!IMEG3Zy8dcRqi`!a6+kZNpdgLE^r~WpMl)NWxMhcgaMhZu!Myg$p zR9houW7ZBYs_$-jhmRSXDm7+pA2Ym+GJFtXvXBsCaRhZItB1&W?tCom%d4t(Vpz+( zVd0p;Y%`|yV75&|nHbErf`+Cz2ZPCe(B&e|sn%RI{l6=U*7f;o;j2~Djl{eB z7+iQv{3rDie!-GCGmhCF)1&4{O)>%^_$@6*$xbuLUu`Wbyc&|j=u-|VlR?QW8|szm zE&3My!r5;w>6jyL5W6f-_nhapq*zlP%kH>KhD--o3Q7=qzs|1@N;WXL4A&6BLJK_ULx zj8l@fE!v&}bVMPRNEQaKfpg0=F0DOM;JN;tZP}bx_5dgl&DiT#a8o+$`%unu4D@!R zC=J{il~`>zTkHaZLI9h|7JGO3{6HRb%QC$*Ztp^GZ^5i;Mfp z1FO^j%wy%vDYKg@i;z{S@sB~6II+}MwxJH;Ip{&uJe*-V;$)C>&~~XR^ChzbwN{%{ zdp2y`datu`Sr6=CefR+Q2CNx50Zr|kfeJ%+Sc=juudeMnwTzlnw3Th)TzuClGq9)e z;=42X0Cz$QdgZHMLP6Gc*>2p;_yUwVzIuKb?B56Qyt~L_6qkl5*>r_k)ue6PEHz2A zVnRja7vnYQN_4RycNZi%b%Z7WK(~8I#=04C7T~eN+Dazfjx3HWTKRnM=qyh7;Q>?= z)hzqj#zBg|VZJJ(HDD((E)}ohaXfRzDdQ8l5PvAw7E05CynP#UxFe(Ew4r4+Cbs7I zjrpjr=xG;@dYn~#V;W*VnIG{>oE^hUFB#8&H7jhWzjQw>nFZ1%M4<&5|m@F4KxF1uIYOPa5tL7_oumgG4 ztV(Zq-w@98l8ehBKY^ce6sgKn(%1al$)h zG|-xht;UgsJr*ooL|&*$?Xe-)b51^0asDMnGVL1M7j2gubP}W4IHug_&b~dsz2p1OD`D`+j*eol;<7tx$ zyCcJ$_)LjCcq~g9sej#^k4P%_uU=yQ=s) z7yrhv;B4sR2RNa;rjI&HuNXvEybO)r&jK{hbmm9;z{Mg zP9l=tr{1_;WNttkWM-G?MN+{g^dh2WOmQ$D+GDv}W7^odk(DIv0=Lv%d9kbzmVxht zq|FP9ZLY6r6u_R@D?6f*t*LFs(|4KiBsH7QJ=WYVui)2-Uy|Z}Eq7e5vVy*yR3;S4 zw`HLl6$(1X1-K7nu+6`eeMDjQzB0eLyvW^qGN7(9M}WkfrDjy<7of=o^Jpj3wXga3 z{mQ!W`;}*P{JxlHPIBolxazJh%olC`%iHZTYqwjry7j&f9cB3mr<*uw_)z*qw2RL! zE*#?A5^pe3%mvSbe&^xiDm^EMo%H`W;!+Lm?ZbN8)mtgj@hw@u{O#>}yM?!kP=_w^ z@E3Y=rpjmI@=QW&+bDgFRg2IWygP3~Ltt^M|HiT?Pc{1zDxkS%J`YtHFc(UtGc%LJ z$H)_vg}?e^9IZ2+Rrc2etxl>%%dPt_+!3Z@pU0_-EU{`dFyNuCMp-pzVq8rF$ySZ{ z-UPoEk91ZJbF^759yc+|m95atCKSGKgr%!cfKZJ<4WnUH+(dSxha=Jspq#9D;Re*l zb{1z|-;?cnKdfUG{cjck$^)Xmy&T!gl=nx49+mbel-J1?oULXpEED(e_#ggDS*ER# zjM9(~w+hlZS)*8>d4)H9fd01?Smo-hSf{TfOlGxxct)3P=b<;WfQMDpg$uIqG1v=S zcz9;GKi+K{w>EueP>;%mPNr--ZAHPMJQM3Q%LVNn4>$0HIXrX$MB}A~LFH9(_4d(x zsPOuk87e@fkjOyPZVzH4B|v7b@#Q zmLRQJ=)AfR39@2yF(LD~x$SkKc3r454fu|_P^T``oi6k|3VkmqlqI8M(l;0pMU?YA zjR=K$)z&?uE!8b#W^f48sf;O~x=v)^!VbWZiW zl>yhYC(=Qj(@Y0JJ>zT;l&iBroLy&wID6$1%Lb8UHjeT@ZZwL_njRT~q0$*spJ%2^ z*?_W$Gi$GBr(fGp@>-fyNkaXpHf#`itrLw(r2W)u8$Mp^Sobp6De%qFwSnXHg1ugt z{@R9&*IVrMmg(1Vur?m0s%xxfVxYDJqR+o>!-TDt$DtZnSGr>gjuS3y9ZJF3I{iA0 z(HZvojOo{DjLx*zXHLIPW2C$aC90*ysL^&BqqFSwS<|o67@cje&z^pr#^@Y-ea`gj zlZ_G6Y&=FvN-Iyu7O9M1zcE_0ZY)lB!^bBN=i2LYr(gT{_$M0yhdJ3EaXLo(j1HZWKxqn1qpaA(z07LP-L*z+I}z zC2*rqlE7qHq|k=E-4+Urv3JBY@DWG?fBl$7HN&vapx!~ca#xi&c*yH|jh~;ADEHte z66MNSc<(e#+?8k|5y=DT0ln)u4ZTMeI_Yz(mX?HRQUAYs`)~&3vs_IlAc&|=?;oTs zutzg;qZwf<5>S}|SF+*R=*?8D=m?S(>&Qpwba)0meO=gVdO+ElU`15Kh5 zL7)naKbwemNc=33_)Pc?dEnSQEgab#Vm=Xf64t&#w%JML*W90cnvI*+dwx9~ANph*nS}aBryo3-9#jLJ zw8BwsO+_ECi*`dd98~w! zt@Qe~#8=aUd(#83S%hPny6imDfxPcj=dj?kr^Cu7uLS z(qFhY{bE|Lo9<(~odq(_oHcZ}&&gSHwM|YD;?s*f!=(YYlUpFxCfAx)EPK^JNJ7uZ zfwn7DV2hZpXw{VOv2JZmtD+BtG!g?CAWZ%nD4D4V|7|n+>GDJ!tnHg!1Op?eCIvx!9 z>=~#@wvLA=Qq@E1k@;JU%WQ!gTyp3#o9U=+$XUr;EJEO|25MUW$8R*FMPf-#KG+pM zK!rp2nvnJniYgW(WKtdhueVgO)<(q$7dsoaY{8S0;G@M4pS)Y>ML< zn4^&SBiCXIg5dk?edBAcacZ;^`06ovDx5;PK^DT{swYpND zV@o`<>c`(gSx*PtBcFNt;4-Z?2KVN=(#^otmkJorT7o>mgF5bK)|a^GcPJsYR*c<| z@At46_3VWVKdCIMx%X6C-^0KktUsMIx_<}r*k+fin0I=OL7uZ(wqGBrW#~o%+0xL5 z&nk-7T1+_cSThP~@US2hvUt+Mup2%ay~#ayHA6{g8RZYL_3J7AEB99IE74csw)<`E zyUT5P9Uk(_lcfo-$5*F~y0gar%K~I-BeE0}w({=7{b|&Y*t3Glohj!vd(Lb2oY(Bx z=t80C&YmHiPdj_gYxZnKpdbo4d)A$^XZ0|g;0t5V3;?SROyYgA&1`2aAuVWJ`42l; zYKPER!c{Xw?1A5mBKi|Y|uKx4wI!*|`V9lIR+ zrW?*9`i7>v7(8=WF47gx+e6?hr5tc~f&-jw3 zj|(#Nj>?rw54|JY#8686L~w%!I5B#`WIo@6lzb5-iLRY23_n)kW}4rk>DSeV-@4I< zaOe_7zCo2R<#J`T(HoqZR4&)BB@L$8+D#0++$(7?{lZN=Vnbg)oNeL1lMu7K&GzRF zUclwy+y_^7Y}7QuZx)U9q==jOY7jU3bP_R=Do4gMcpPiSO7trVU^=; zH^wRp=d*Y?Pl`Bv8K+Nixb2=E#hoeiY)Ekg#&3eSv!4x$J7+W8oOLpaBfxMLALU6A zckWk%I2OU49^$rdintw{BJO$K*fXTKZ!n4@OV$R{^?c!H{XA}AR1&R+1RZs>9;t1` z;+yc(C;v2ZN3mH6t5=Wut0M}_Z^CzIb>_>#tk+3Tcw$Kr#C{XwxKS*bj|B@w99M?Q zL(?4hSj}HU;#t$&T-P|cDLWbPWm#N;uWrRPVcp}r$QT_9bi|H%)9eU|C`9QsT}TwsWE$P)F7 z9!&O2GK8K}5_L=^foy-+wO)1%Ripfw6b?@c22**h5#hJd$n10@76QkbI2M3hk6Ny$ zRWy!kuqW_Ii#$LI4(_;g0kgK-=L+{Yz*#mVU8r7uvVWSo#&%9}AQiKMmijD$_rxzheel4JfhR20 z;GsMx@Dv4{yeozovptINz*L(;l{W7S*S5W%JE6q3=O>g{yon8~nUNb-eD`$4&p(}t znH5uTieh+nxUSB(&MWbN4Ps-Y9qe+86GjwoNbJ?wT7|;2kR=cA7)9EJqCO zfq?$Lmv$BpD3sqe#CC;6;AHFY)yiiAmoCyiJ1WG+V*dl;1M$ua-)Bd6=$5ssFH4xC z1Uz@4mA>U0`wd%HL1wbdHKZ|c>?g(5lU)O3|2_=A7iY4H+!5otyCg54m(;JHFkiAYx@yh7O8GU?+l5h@F@NAv1$s zDy6(w7fw-GwQF-PF^CGx)LV}#KG6GZUDlK{R-58>-l<5u# zY-A;5hSZpP1_Dy_E_A|7R_Fv$vR!qh56K|Kw@sogbV*SSoJ&+wf*2<`bI66<0>vOK z-$tbmZ5x$>>_i)y9Fw#mACthKRZ=Um>Z7Jv&0?=7q-8`?#X-*i%oTEv;V~d{9!V1{hRHCk~lYi14IgN+fpl?l^#yOOB9^ z93fyYAABXZqmp#v(6lb z8;MxgWu0N>lkxHWiC7cm)ZPEK8Wtnf^j=fjQOE@%GN_>?<{Z%U%PjBzRLhAE4bO-# z(R^f9Wmqea4ymW0g8i^Qymk>PG`w`LWTqoG?Lb8xs2(ck)ev!89hYL4;8}ScKB_g6 z0*Lo4LX>pv!YsQu({DN9o4@J$t#g)*O*A5%`DkPx*TUnvmx}CPC{5 zoM}Wfqb2Ay)!^O6iF6SWI;A-g+9a-rH4hhRVT+M(#sNnKorIk`y>PbvM0y^q@yP}IoL(wPvj7eVi`nTrel5TFIx+F<&y%G{Cox6|r`BM}{YGb2+L(Os~P=#ECBt8nr&PD>d_ zIz}RVw5BU3!V}Hk5aC13-w)J3L_%yZF%n`}r; z3F~L&6AgMQBz%fN8y#EHQllbm`)QF>b6g?rXJuUPdQQf*7K+oX!LT+luFU>tz#ASY z>YN-5XBr0_9^f4-L88Vk_==njj7N&Wch`qqH2+PZjRhDac(V>5m$6}4aak&ckvMrY z|Eg-{RcF*%=$qrAlkuNURKfajhM*6XU4Y$2Vx*9c;w0pKNe>jBA(z0$3e@8^O02(b zs6ai*TUVf*g-Zy*FIAgdA(N&yn1gFcDoQV zvGT%i(y|0k*ALO0KF-(>RNSTDp;k(Xkz!cdPg zIuF7)9Q>aB`|D={q|ju~8d*j|>^WE^PY2C6{@NJLrY;(CK`H(^7(Gx*r@{4V2PqhS zyG{HW{-$X^DP3Q4b@@>F4`$}{p2L}Q*AdCB&1TLK-k!|#c#t9A{OjWlf-vfQdb92I zEguPON0UsF>%ut7`;pYzC5ES*lqW-uzl~zX*qiAq#(KnKh_w=pOIt(Wv;k>>}Mt{LI-y^RK{1 zTb&to*0V%-p=R_~!xHZ$079%w{Eu6PM7KV)%X)ZN!*msQT%^@rf^O6p+Ks>W!QJfp zWA*nZW2LT<$1^9G?2);GxJ9_6pYdXxfG2Xpi{XmNTiAv&c?q}T316kXH0$=#Z~q_c zWh}IpQOTm%%h()*bf3m=EA4M}zHOHlzsyqFI_SIq3Lvx5HYqXOwT5Tu(j&mPrLb|a zGQ}f}@@iXk_Tc0C1)*BXidiM*C@U^X%z=KRw$aU%CPLXO6i{7~Wd*x!me@7+qRwJ9 zSapM6rJ|)`nYe4E*glmH7S ztEXkLcg#gZi>ABJBu13J4-o7$_%U7i?9*^zbG}w zIXkgY<(rIXRp}w?k{GX5w%~Pe095)g0`!P|{indj@hzqNA4|pKHcgi}^agJ*zaJI4 zY&Jh)7MA{moPi_rf0Oq*fvAV5%Iz{tcjARzG)}-rEtQ57f zFv=+q^v3!)6mLN=iW0!dJ_XM~6NNCY5yEZI*8;Z={sEbH80?Qw(Ul^51AmLIfDe8Q z{5h0bdSJn`_FeeJdyk^D58m1MSmX1!oz^qt`*?8AxC-j3ws1rwZRi-Uqq@RXj+CJ- zv;}z0-9SD^Gy!MB0-9B!z3gxvSec*wb0nr)a@duYMj$?7Tv8q6I7j=`0TI*ErwjoH zwW&o|+=I5j#5rTu{a>;kJZN}iJux+XytKn^QqvFeJxwR}M8=GSfp-xZVq28zPdTw@ zJ=A?oHFR+7DKg7j%RYl|h*Z2Lf|JwV#?ThZjhscRObmT?AD>Aji7lC2I1TT41rZcgcd*mKl}VEidOD^6Q+QN=bGnN+!G4Sp(C3O?^MpiD&2u!#(#WCRfF zfsMZ92z& zlr{n5IFCftI=siJPZRD~BtTVyBbK1TbAU;~>v^ku%&;%PZSNj?B zraefrslh)HGp4Br)f5Asm@68Rx;_ARN_uzY{0zC&3h^G+5MR5Ohah8L#D-#U!u^d} zKWg1jz4ym1Soy?btsZ+at{}oDoyQVkffp1PDxRQ9*qL-8^Iu&~4Ddb}oTy$xcuadn z)=;kIv4P8YMP8ZmVHrV5yL7!knXkNRk+3ruSPO6AP-vnxgE<0&cvKnTcqQIsIj(@o zY2P?&xUYc;A}7 zW|Jm>hT$F~xSiQifpIz8z3K^th+=}wk-W<2bR8Vu7~z2IJIb_0UpJcC;~vzBqnN3d z6-r&M=X$?CN6tc!9sv|^?~lOU?Z9DT+H99{0~b5xG&3GTy=?V~Q;jqBxb>-aS0UjX zZs!r8-&u^zNTAhs5JW9B3BNYMtMbSuI={D_f=Y41jN?=6Zn&F(QH;Sd~ntC(!8c-x%l7`c!A_A^S zM5%N&VzUTFV?Fenv@ww-qBiauIVUkK$3$sfEnb`EvE+4x<6WBlK)iUZX$$l*y_wQw zE-VpII-0jS=i>4x8~jX5!G~g6im|qnX(=Y?9fJ)mrJb0_$+Z;Zc~eWtV}?rCQe;;| z1!-d~#jJ#J(@Aa^Ga?hE@NTC@*Cg_mNPHZoX3Rd!r(hqajIfggO?ZrRQ%_#FYSVCr z$PFyvj_5}Oy^;;jN%z#x`Mf+nuIRg6tM4H{!t13UpjdkwXk|OIHzDA{uH6**b~4y2 zNF&Y+4)bI)X|^&ucod!Hy)O9a2wZm_j zRG`+KzU4v2H`To)yN4>JwxK?<8!sO&s*XntSeNa8ZpX^*%pMWY(g1B%OXZU}Wa3mR zpy|c;(aK3xKs4)G1$-`)J@l4muIw@U%T=~Y>(qjETAwLm$H7n1`aYc}t?#%nbQ)Tp zX*lI7`#8tSpVB+fAaR~j3(!{t18T-t6GXhI1gkMBVH2FAh-)zZ1TaJ~4?1lrV1=lieTIUsg{gfMSdyuI z4^XJ@N4@X0Hdwe6In#vOsZDK8POhtbe?6*q*Q1K46H763{W&zXKYia@-rC*7)K2gI z0h!wGlK_2|Ozpyi7?$HdDpNaR;OUs!cQ#1wy^)IV6v2tn{-ZOs@zXtX?z<7wHBZ>> z;3_fQch=MM_Ii4X-ED4a&rX=yH5Y9#*m?4dh_#v*g?z7dV?P&J>*2^=8mv{0v(sX& zGyU3DLI1VNoweR-qplq2Vy(C2qd~N(-vWzCtQ8#z|1iEpg8&s4EfZgqF*>wPrNO{m zq#V;{=#_T#q)%N&PiLAoZPi?x=9qJl&Sq8V=k|^^1}O1}nSr}Dm7zF+_NJ&39Eu1@ z)<9>>Z)4)=wr#R+ngIkPyK!JA7}izZP!H%@J)n`_S{-01eHa0f200kiu1#|cVd9yK z6V;d`DdrnA<07g57Q$UfUNdfFAyHz_Rx78|^Wzkp7y=>RZzgF#=2r6rv90{|?|tO; zfBTV7zW=k?%SrGhtt(bTMRQ(JQRL{poee6&j8{dS^%c>u42q8Ej?rY>GUH_~(|P2K zRM*<9P+EI4D-3$|ApNWOC>j{}%SzdM`9gt1UOrg$pFG-fJ-BN$rW&0xCz5OQ%!D?n ztnMvk!!C~AaRo=k@Ozv2R@p9WcyIVvWfAC<-utC$!rYJPim&xPUC)d@S1cFvxnf)3 zb5$;JVgjNd!1V54F7@VQj#rsxTP!dGCB`SQlSsq9VXf+Ecwq+<_KjIiZdz?<-vA{l z@ZF^xS%n7ITs1QBBI1w}u}HOr#SO62x52@Oq*8Hw#-+46;9i@-gf|=&-kcgXWDS31 zPquyfV14IFxaJP$tU5yrX2~n=zM?4y^kDGIK+BQt=72txX_xv1xid$^w3mt#^2u^N z9#~;tU5u?PFSUX5P~|brfb(JG{)kQ10a&#)s}@8wmJv7IRpSh$p&=9CLxBRELIm{4S4*HYiW}{|w?hB5o|G|5q00gd!#DAUONL&(4y~KSXIxI!xB!o{2QK0E7*s z`TThGc?(Q`-WJJhq4-&m<}(ZJEN71vJbAvBL925BvJnDi5*{( z*zxA3bL<9+NeA0dk}^u*nNhLO&a*7j>FScX(kW=E0T`q2&`8M2WQxwrRD<`Xy{ku`{~WafLu|L`Hlx#WAp)R^ndcF5$vyuQ6z5Et*A2ZINc-SS{Le zz6>Jj(*mt)`aZT8L_B4{EHuT;CbgNZZ?7+|jbPx>V357^AvWXy=@I zWHza;%w8L7_DCse2)O7b1+k6=pCL8jeX^H)7$cx;S-vVf0*dUEbHq)-csk^3rg}Ts zZ{1MX%Hqrz_TEOYv+>nnm(1D(ZeuLsFYpQR7Yt_c7c6N7;>w@~2I+Gfu$IVB(uU0q zSc{-vYq52oO44a!$KTC%f@XGs`hi6=H$uX$BphT`Az?eJ*%xHHtJ&~jKW0UzB65J? zQt@5GTpwM<;PUIGj4hXIA#5(oB(5d`Ag^-hR_n`sXa>@zs>}7!m3FwIRr69+fG zve0GY4%Evo-l{i0D<@J;5+htd3MqE$oxIvJg0=Bvz9UyHJc-9_zt=>{TvB8eTPe5k zi}7F+vSh;?7q&X|xL8PaCTCn$ou!jsw~1^!{W_?g4r#vtSo{9J6EMc!61xH%u47n+9E?zeM;Jq=CiWM3LAob^pvCY ze7C5jlgPtcegSXgpc|Smea0N zPTdXRynnjR>a^=*a&KJc-A}(xJW&N3Bf|5A6003F=`Q826$X`yLvdd>O}E2Wj^hC( z*5Oz?rV8fBB(~u{8~5VGJyX~|eayhkHm>u&r(Y+`dkPJVa&G7M6U|W`h#`m;ZJoap~hy}9oSlm8c`$dU*)Z=y3)10AV?HkUfo2TpCdD?X% zIH&5&d{mzNjf8iXSTGIeDK*E?mu|E|Uf;fM|K8mYu!+_w)-C***F8q(BeTGl54 ziRD>K36D%(vmK1>>*yU~SBcxD%r-?xiCRc$e^}6p;c;QcF)d zF)3w+ZBC1zvs=yPv!p{|+nM|CZ#z#PJOiE{`SctX$L+s;lvBRK+hOPd9az+RH;)F# z3VBEpM_0)oQ^~{^3B_%yG zk?u4P1;?-Jn=RoZy2K%PQ1_4MPwavo3_emw{c1LMmx^o*n3!7S;!BOZQziQw0wz|~ zDEXgNvKM!DOm^{1M)(FQ5`xw@M;F9XHmu|^4cT0HQWwgcv=Xt2 zSc!V~puXu%4CQeiY0x$K8zql;BTe$SFP7AlZj`)PCC`|s^A0a5;0Bt&|E5W~_ObHm znM||UL~V0%kPrS2watgO=z=N0R1df6{to?#qi!g>D?OOoGx&X%fV6aeR!O1Jw2o|| z;xn-eqD4Pe^#5R-Qz>R!1S@Q8v0cRW89(=r*d4>a*6!`H5m0G+oDxum>wh?$f51|S zOV@WCP_xMqX_8{DxtD@hn4xbhP57cV!^Ys>d!`JgHJ{3KwCNAnrv2M6IKXt^2DH*2 zW&Nwlq|!~>3DzZ$WL<({L^X7&nCemq zvW&N?OL#5RB`yQgP2}s<`tDTLxRtICI-srt7}>e)0FEFwzF4B7Er&{O7rT ztoa|spF8|u@ejnG+qD(42>)OFdA>~VB7FJx{o8NWUVr4dFlP~dI{v&^0Z2vo ztB-i$=d-1epYMx5FEJh*o;v1lFR|!_@X`45TV;S2;r;RFq82)f@UHlCi!s0Ow)oTR z=pwv6{@gBenUmE&>@{zfZCZq%i9i3q&hsw9r+&|0Unbv45pIh=zun36(cevAMOF}# znJzJIa~kLVP}QEAJ%L)TITi8y4Z_NsjPn?q$3)@?ZOT=n{m<*ltb~OM|Do?t$zp$l$YZN zNYqtfE}0}A@i}66RP5#xDGI}~Tn=YYYpJm9FvDK#aL&~sugEO?*0r_PUTq{|zlOlu zGqMf=h~;YxXUqT6|IH$Aud~IxG2fv+YSoRABePfrBYr4TNpl>fOL!FjoBpr)sKbEe zpb7}Ufl$h>QSBH4Y{QvpIgnx*K4nYmKzjzT8FA_(#mM;dQ$2>KSe@SZBh^a2V?ywo z@Zr!iback(Fwf^SEYQ?C%&&W3@Buln5R)YE9M1ml=HxpnmeaqlHTJ~V413xt2l<}{ z_EHbl_3_{4ok(hIH5IAhC?v_U4p}pL>w;hl74z|+S@s6Vd!@6q845zO$cm{^CT#^_ zH1N2g)GiLYVO)kSN(n{*IV=MecqHw zJF1hI#g}RH`O2Niu^Cke)8aX9X~3p4Qa1?v}6(|$* zum?Rv?CY}4YRT+K5Ic|%9O7+NBGwAz^0v(^_U6Zb$$jnpg)p^oybFTa)&=tDN6LcH zW$bJ(#4M-_bKtcb?#WgczB#l1`kVfj-s4;3tTyc^<Mw#$LQ7w0 zCF+!Igt^8S*hZ)E#cbmXl#A2&V!rVO$mmN!2YLaGLHmt7}lTs+*wdJW{oe zXycaZlxAOQtF4hh<>Z%k;9C31{Xmnfyleuq8Kd8%a096um=5D(5c5W0KW7|17ZL7ONsZ?|M>Yw)p+W+deXFU~}o zI^vCf*%oo}#_J6lIBt8pfX$t9)&{yZ!KK=#Ya;nWOdv8-`)_ z6aem!>$o?}G6!Gjq|Hv-1bB=$l3LlqbQR$j9TOR%DF1L=>hUlf(@c?ith&%P)I|ve z<{=_c@&pk>W*sD<@pI??nx9o);tp7bc4_rTNZKUuv~Rvd$$ug7{M8#)v;tGToM+O| zXSH@CLa?q;!AM~k)MV*3rOcuqNR!ag5SjvaT4nJ&=DVy7nL#Hlz+1|-5V4e$lsrry zqjAmrxI2A&{1LDcw}(F_ zGpgdw&7dXjc(BNYe7(2x)-t*MAX;LvJfX0md}n%q7)CHB9lRrxq#Mq8S)gN8H)`SA z@i8#hjEZt&p-FeC4FisJ&Oxa*xAy<3nLrb*p&pu=3YE+7VRH8U1IBN+zWHYcOiw-s zVA9e!4M~FW(|B;^UH0asukr$ZiCV$Z3bw-;%HRK3M*jYtSy_MM zWm(1$SBYvUv_#czoP~WBXa}!xzUb z$gY15`tZ4N3y7KLqJ_U6w?M)hGu@%%%5{}Byp)>J$VFJcjv`88d)|H}DL03ddyX*h zWrHtT(}}H|d?a^?-#oJ~+F^?_3C`|@m7EIeVC6CF(bj>m3+3diYZ*SZYaf3uMhV`o zk8MJn1}c?xC6+eb5v@x@)*PZO_6xnqlqS-20BA#XAu@>v4Lxf=A|7;lN1k1 z+t9Xbi2=t_(rq88b=$Bl9MdlyM7~=t<8hlsGz4;xZx>6bg(-PI96Q!I(a(f#ZOnLgG5!SO><=z6*$*&>YT%6FOzHVg)8Bb{s~igmHBaBjcWXKJJ^8X{7(8BD99v%+q_Pg zD?+k>Eau57BEG_qQt{UNw8R~+2vt^ZJ#I`(D&$kzk7rvL9%jWd{KQs}wpBXJfC*x2 zO5u^ZHtNvo(qyI0Dg_XB;{{wEtG}WeeI)?6e26R4Oh^YT9!$lvp|+^ALz9uXX#g@F zLWM!e3P;Q)N4L#DZ3fYen~ZJU7u!+?h2q$1jRUhkkZv5DZLft)Xo7;{0J3n%2Cf?S zpjqoE)+>-T+|w-xA-1|Um#w`2jeq#2xBl#B|Jn%souB$2e{}S7fA-O1Eb76$pwhTR ztOUzO@4hxIgT4QU1!V1H0r}PAC8ZBCavz8xcuqf2`NSP$fAJ2@X5M}^RX&L{F?}C< z&3(+&!Mr^jqQvkku}4ij_`W!#946H73QMzrEvbRjBAYWP*;G;NLBkb9h>>Bx0cQPC z)LB$TL+vr0C5PHHnh|`HSpW-bSQrBzK~|g$FZ>8KCc6em;~~8xWc}|4?cmhomH^L* z1k%(pg3i0~*=Qf|yI23NC#8f_xP^&M8J1GtD{3}I_SUko9?7>eXm~{W^aih|Pb^gk zk=fvHbDWTfVt+BjF+<)=iom9}`3;KKL*y7R`e@NeBI*Mig2co_#PhuJY4rEJ+PopzA0)>qL78d$XJpuq*6^sDr?>Oph zI9uVwjrXXVq&o*qEHaTyN;hGxz!834IG@|6o_eZ#wYJ>jrR4v;1OIxItsY>#hl=w3 ztKmD*yE%<_f4J{W_hc?!ZHWy^#+xT9+HA0s)7eeLaNJ>GggB%4z$iNaa!VU%k}3GR zmnmj~+9TK_02jUfSn;Y!05tIG4G6xu7-goA8a0qk9nute?j99nerD9c%=TeUEh=ei zdm;!15gTOichIWgyTXgj1K#`u-ZuvKCkd&D00RZo6n=DXc<{}jVAu_h`5S!RsZ+=- zij)WTk23Ab)G2_<69GwENRF^cOcGL$h?(Q6g;Bxv??E&Wr&m4lB$5@peNF@m-+)(H zBTS9gR^^ZEH42qitK2`h5l|sBT!HMDTQ&&J-#g0o4-PUfs%-yWVNO_{Xf=iI2w>}w zx5`g%6{%Ubn)*lEMQj^&UpUg`CKCA3zmgM?!TSWtG<`S37zCJb#$>0E(jlg*`Lg`7lcOPG9ml}RK^STNgR zLg3ryH36n=Mf0(EKX^m2AA-n+HXX`k2Hg3E7KmxrFjKK^LWks1)S;G?hH{5eDj3ym zMheECXr~*VcObO(!Xt0fPi3&B3+c%hP0}k-^6l1c@Duc$zd2fc6`$n>9me ztt{>IONIs#*L=}jyoOeN+U(vt%C`$hddrRKsOJoeLgE|slz16s#8IvxlNOcPgu)HL zgn|&$lrq1olS{{@6lA+rxYMB=e8r?uIi?b9lnL5^#%(@98-&)?G)cQo8--{CAJYVF zF#d@)G;++8G;*3M3JqqeH2*bwg*PHR3dLx0(mO3|xnz_Ga>hKCU#KIyPvJHDEB(x>zFO!RA1zs|s2NI;a3|c3a=|0|HhUr= zA5zmW*fULYv4O$~URs8aMVt+?a(spW8*o9KKPlc|Q#gLanlRw7BRD)kwYqPOX6+sz z5vZ!-Nj0cHj+tCFU9FxtCd1?Y3UKd(xec>&8MyvmJT=-2%11q8y^azv}bA*czrP<}PijD;w#Y+NI!Tv6q2Log8^ zdxm+0MnD1)P*bbC?GYjo;8fcRuSu=4Cg#1duV?IQ5wG=Z2IAn`)HP-z^NTX{8gc2g zGTO2l&S4luc9|+!^oFaJS;p-<2HVod=CnWMqf)DnmGu0udSVwjYM`s7!VWnChFvKtzYax zB|=?b&>-nG(Skww6NRA$MRmybMOq8@Gw#w`DX>rtxP%9IV)=o>G2P7yI^k0>Dw&n9 z6bV{_P;6t`w3EhKBdLy+h2enD`74P1;8L*?mKlC;Dh5BLvd&0^aTtlM4AugAnvpbw z%*hyu?e3-#aS$Sv{h~Q-6bk8>K4FI#F@VzbXN4Uf3y{TFVEjw=#E}`&SK)D$C>EcV zNHU*$;+{Frndc~SsH=(SDkspy5p))bnnF_wxhK9h#*KsB7-{{38GfsLKfr1Ag(sX|6eBt2a zlk^1B)pSG^eN;cByXuFo^_$1_y4a0+v&J8_ zqibF4X8kx6-{@KwyH!7Kif?qSi`}Llx5PKP*2NAt-`t@edZI>eZ~nMTKlDUz?ri=z zq91yqH+MIG+^ZjYqBlpIKaS~#p6Jbe%^wfwho0!o{mmZ_>4%=^&4bM!C-g&4^yX3h zI39oKTEBT*KOTv1bghd$sUMHUH@eov4l-B56Y-6%b+H@uW{p2;RM)!L&H8aDzR|TV zcB_8e6yNAt7rRYAZi#Pnt&82EABW=`UF%|Z>BsHyjjnaEBl>Y?e4}e!>|Xu2JHFAi zE_O^mj>b2-*2NyskNe^qUF%{G>Bs%?jjnaE2b*s;m$S~_q8y*(g(j?>SNZW}5+TU( z3^^{=_$)C*1^qbJm9&5>;<|aJ91=~^oLp7ee~{#0gx;fY!rcpLV8t@b?@gxWnJl&6 z$wfnK2fQEQ`4)+W$3P-wls^DoXTpz&W4Fl7-L8sJdVi{rrv={(ts=5e$dZ9EEf;0L zyIgErxP_cPq%^gR3meEqnI2It7K1~Dl)l&?jTFmCYE*XKK+%BL1%yqFM??wwLr>6LO4UG$S3W zj-hpt1xW}-tUSL+i|HTHo(riNi*Zdd(~mjxC8HV09kmT?TbH+cf6dTx=cg2QYUcwD z2yScDt^RX|QqFqg_F=1BCXi9qy3BKmqiCQ{t42(57H+JWB2|v!k3qsvKp7UR#KmCR zQG2aM`dC;m(d1bHW#O#iXfl*@O=ukN7V>9m8b6tc@_;3a9z6|scNjf7y=y^(M*|C@ zvmUVHMs=}`OT8DQ*!on(58)7S{B{2q3Y(X#@d^ZU2Ws@9JCJ-c$sLFboX_PBEZiMf z)b2nqwgX}+qEFC=p;#`K6T~A{?5bk_s4Z>9!Ugfk;VLop7~dV5EW_qjR zU4S*m2;bX4V84%jA|sX@83cLQXo3RrsK^^gjSAZrMU5CpjclZ$3E}}eyjui|I6yRF z-~}a9$sYJA#Yvy`UzyKcZx)KRmaN(iWC2Oggx2`rOV|S-5%HZdUDlXA;OxoK{RAuoAg z&Nzq5iS!HhLnE+=ujFo=$U>n_tp*8q6^?sqJ8w(h%Ga`m#mQvMjwD;~MI&1Z%Ok}! zO@f_nx@^fgG)UdiR5w;5*}@>}0vqV{_hsK`Taj`W>h55@V`rAZ!Nf&<(bvwvHqxXI zpF2uLI=9*C%fph^pRM+bxa6$JiL>bLBJL`#_(^X6+|l|xXIr1Wu_#Jk9r87P<18_% zVh(T%<}Ccw&`?-V^+4e{TKUq-FI$wAJr222FB8%*zZ=Vjr7b9G4V-?&WkXW9yjOc0 zDW^nPRy_#3u0fMKRXgXunX zF3K%rO-UHofQH9GguExb(1XHPtKXFquIyu=1!r-!uRAW778}BPMGW~MP|M{2NN=D( z_lFIaQZdjP+?|nygP(8qyniO-J^k!Z;p^_K5fiQx?u8WX57@)IsMwrLyj3C6S21mG zltHgQHfQiQ38O69v92fQ{G}OZCaLvpT!2N#i5)Q@=D54_vjV3V?xGRZUwEDR$*7>X zij~>haKww~tXGX28pzgMEwpvwW!X#bsT4{->V?_2MWIwX?Gs6{>hQry5dC;uvlzjm zAqSUZ=}q`P*n#2kP2jq^x4%W`V*7i>?`(Bnf7WlRY;XSzZo|2HePETp=U=g%w_;v$ zs}ST{{Me!(HB{rG~#$o})W_b*to%l8E>92t$8(^fT^E2{quDu*h&$?Lhs zYl|nMth>t88KZc*tVygYU(2eVHL|Wu*Xr5R_v@-%!EL;*_Rm%L866yqq}An&ife!U z*gwwr+&jKKU^rlmt%rO1?<;I?01t+MHTXSWE+2f@u6ptSmI{+`O;LUfjo9HZE0=*A zRpKeO@azf~(dNC;S;| zB7?4Du&HThMpjyu^5L^u#Fsug%9R|F-Rlxv{0@Kl=uu%-%+x_J-A8Z!LT~cM8#QfV zDoR)LJ3XV35i(?P)Qug4eaKwkqR-6O2w!q2C>Q&S z6I~zKUb%6x&#D+;)x}Vq&>5`&wOyK>!>qlRLNa&Y-X=xa>cZ1=;K1xDyAV?VP2$30 zz;0Da?98f5vrBY`z4qebMcmKoO!05O6H@sqJf9P0zunh4?~6-Q9Q7&$2kQgZnzhs)9XB*j*SSI9S`h=+n1+M5 z*;shkbA-8MCh{glt|=gjr8Oy+&t~M>vCkhBx+Wsmt`bLe;uwhp46&oKj>A6w@F&#m*^5?|NIL?2d4U7tr z7h1Sy&WY?Ul9x>Y%bY_!h9!}g_{q>Nk-Vsa?x+eQFRA7tF9ab=s^e@xbiP4erIA$aV5P@eb&e$gCP3W=zFuQmxzjPvs+zMykNqM1Dma6&zw4SqbD zzb9)Ad05`w<>& zM;Xle-(815n&6aO5-Ux)+OlxlBjUVr=RN*;-QlEB^-)mX!CTu+`N=k%3TE;cD~D22 zO3Wd~R@i1xtX8=Hh2_%4-G1avB5$ z;4%hARgj)wzsyPR5@rU8WUlAkB~px9nhXr(GTtUGmtm-}0h|DM-e^AHGvlWecj{Rp zBWtl53Pt1Sds-{&?_qbUU}O`7^N|1iX!e2({`-#5-o+Etz7bnWGXWFIRIf0! z>*De%Ds`l?zZsYzoc(y2|Zy?HWKbzG`A7= z%AC>N3nvrRblKS&GL$i83m}y2GPw~u;R#BYdkJIY6$2*S03dq;nd=~47vr^x*QI#f z6|a}rm4IOX&s4r;SpcLYAY|B8|I1djP1eKvwKF|6heK0TMch4arLds$^%-5aW8iNk zvC8<-1bqE4IK!i3vMdxi*uo_Y+K>VwAlylaakL3A)pBl0-I`)zbNKd4s`OFNbB&3r zR3qYJ&Sjj1Fs@>0Xu8sMv|j`;YF|s+L$+&Q3lq__L|NEG_nV;8t{HqS48Re1R`{p9 zT0-a3{Vhzc!3Sjikl94zy=pFns8g3d-n18elZm5?`o%bME~!`ap1EPN8%$D5bRS-aJ9K|fdZ7Ia+>@SB)FSv7 z;CK+vdF3)5z^s3wsAaL4_EJ`HLkYNT-i|Vb-SVi|I}ZEs2(dR5hnkHUFLug1My0<(v0p9t?`bO1vo49?2zF; zCJDlnaVIA82ts$w2gEK>TWL0J#TCpJCV8JpyT>2XNT0M_YtWjO^YmG2ckN40zuh0} z<~=78Bg0t&vNW;-aoa0pZ9_h~g(E?odoT&3H%8_drk<9wD57N}e0Xq1nLC_GM~tMH zw2~UMomtt5V5VJoQiF15W=Rb=Qb0)!uy#DD0U`VQtDf=@lrgCRB`v8z&ypIbyd^bY zJ7-L4P$IzHG^&#t@Qo!kuy4p2!#V?5S7b9Y1Z=uR%9g8yy;GSdDUc>9W((wWKyZu6 z(!?uwEBVZ;cPloT8~G5{wGtr|x=96&?G9S-pp5 z!!kS&UMQ}u6FSQ6us(R8Zg@_zFL5=S&%-X5he>G_gTWd6c7a%-j45NR;MqOvXLg=v zAxWwnYBUCKL0YI}c#TU+dxH34jtPd}xc8_~nO1qP`2qtaVi9M4*gyGY{ z$x5sklv0A{+HeQ?z#%;c$(RlY3h=!Z)-%!*||QdQ1lCHAnA2RJ5x77X+sozqsS>VGyx&=!~!@}?!jJJb# za{verzD+0^e6r~Ox_q{DUq0E^SS6GaxHy8q&Ffc$O6l6_uZWG&wptrw=%Zkaq%TJo zZgQL|dBJuxsHP7W1xv(&8`sr1T(L4-wQz~xs$I6!)o|I;ob;$onu{LeXR|dC5dbvY z$x}a-uL=F6%KCrT%4efS?c_s}9E6OmbFH=Ho-0K}%Gu)rN~FWtz#^SqG{DV=HY*+% z^#=u8FcFw4L$J<<7|kfAQB=n@=ipCL(>3SgS8c(PBU$TuEDw zg%VZBJqRK5#2T@kstVCI7oTw`rjLhxps(#83MUQ%KBkQ!$R{9xZ;m0*1Z2|AYVC2y z9!S*C1S{F*>x>n*wnqhSV;#r$Vo9X(Vp;!qZHyNX;7bJzlq`P;t34x@2GyPL8H?|t z$3`e*r^>~&;T`U30qp}SaYysGQvbHDlqDFelmu{%N;|Pq0-kdc!BJ_P|HO7L5|b_0 zA0PTcW<)Z`6NV)*47Jk9S@CSgz!L9G)itYBgQnrcl2R?krT8;3gtV=_LqUCV<^JFK z%!P5G46||#sW7MSETZ3DdVvNVrd){j6k_9i43$|d4wX3^`%BkftVEA0Xp_h0N>e?e zEvr-l%eI96PJw^K$0UwSfeL^y8_|vgI2Tw6)gUNvfk`kilr1PtnU&afH0(rv0ToCL z6XC+Zzz8hg6hEL+Y9K5?RHz@89#T0ROa-{%bq9Obsggo$r@d!{y~gt75084}p{{yC z?^oF|%=JgLoe0;yaY0ISRieADgw_{F06{2$DI#qdd;pC%q-vulMA&oS&aFuxS9}-? z3F?lRp@MX%!V;MZZ1v(+lu}=fD&<=THRj0?MP~gkwDTExzvT)J8QAS2fT+COykjGQF4~y{I+@`Egru z`D0ugIJpQ4Bn>%W`xmhdLG!z=fO!`ENwNBXt7{hoP+YJl5bINv{;lb+UNVKn>@!)eu$am3VkVx#2S;oh*Y!Yni8+l`hLbUID|AV;2@GGc1Q}UISS&yI=Q>AK%G#P ze5Wd9)=7=x1Cje1%L2Bcg+CVM6oZhP3XQU&ML8~Q**BnT1hZX)ihaFNoHu;-(W6=T zJb$X0?E!AXrQ$_W6WQ<}29N{lx~Jj2`gZCCGQoAsEVCs%4!46mtf}KF&ikp_7l%e@ zwuaZP*YMag9oO&(SqQ#{$CDlj54jA6;JfOeSZfWBySRqe*8YuMJm_l;50NM(K@~s= zypcSiD}!HykK4o81%DuAnO*(Xb)*X=z*bt`<326#Y3qzH<-z~7lm~I!QeOWDYd1}a z0%MXasUxlhXVPorZ4v=+H}<994sxXC`jB#Y*u;vf6@pyFr3vF?kDBmSjY}=hqmap~@PaSWU9BOzzlGm8dPQC7cjd`OO!?+x`2tb8YMTi)`3-(P53F{Bk<2%!ks3 z*oMk1f}6>z(o_>yZeXqEaBljc<_X4x*Ng~g=qvV%;n6$O>y)@w=<~?}r4`ppDpVaP zmX5((>;13*!PXjX-{ zDrB`Qy-0A_vPLya+rT>$9s=!w9dS{OMXt(JXJYZm>QDy?a&sjM8Kj7XU{@XHb~R4| zO8SGAJfl~s0)&$qtu?5(cZ?|^iA)lM3{bVrA`@4hdg}H68;-fAlb@O_k8>X z{{m$Wi7#o-jRF|75CcT0ASLN1fF(okKWLw=jmGz{{STww%86`kG{av~VCDP6uY3V% z`+_Xfx=0y1t5t91rr*!jHhJIE`=bZHW3%_OdcXFYAAiBxJD}KCuWw+^3f%Y0hremF z5(`%1@Xf#Y6VIcFW!v4LCP^SQwf5()fA623t%6AE4a)T@b@jFX;T?=;_{tX<#2w+5 zzlsh=#~8veVoY!gTU_}9RG!Fwh{c8ts>MIG3cA4551j-=Gh%?V44{mH8-oawr-|!W zMt}!0gy=ndF*!8-g0UAwKlS?=a#$oR-3}}O{D@>?GW`V&MYvptGbX|HLnvgEmFY8U zg@gmvvKO5!q!vqift~cQHHz-&jkW>N8zm73ZR+oJvI(`9bAqH4b6}5WMav>qzBFl! zWI=jt^o@yn^At4;?vnN1e_bnYy%t7WO8qnD%bg;XZbIdAdGY)g7dPg-8|*2_?Xa@8 zR*~0@-@9mTC0qHMUwQDJx4rFy$NtmxgNJ1jvFxG8AN%yXKJkTj{O%k7Tjr0o7FKLf ze0kL#PZwu}5SXZLDPAwp6*U@AtJe_DRKDUpuR$r|=kjZK+~y}^#!fc>5J*^+eN9#H zd|Z6xI}bq*lYusk%AHVZ`Kl{F0 zzwAA@kP{+Xuc3v{(i37R^F4zj1!GFlgV%~HhQCvon|Sz*EI+Ldjtd(c3@PMM9jz2< zWz?$MkyQXbr<#GwPB#O55w=%YOP_1BlzU56=?VD$FB(Op+$dr;qY&uc+uMhVhheX;LTF}PZG+!yIa>XmaFN=+7#Tb~ z$2U4-1@I~O`4T?4%rA=4ZJCR4I7{U;PbhcMC(2#)iE1ir(8`%Qs&RDSyUIcuZ#WLW~u^yrn!35Pv9&|x~Y3)cU&HQ5UJ7knGF{Kaq zq(cc`JT=!Ud+hd---Vsoa08jU?pu{s5PhqfWD7-JC)GZ93DDKPIyDne%NSDVtx!Cqxx0wr|H{fatjV=6NjvES$mmuPv8aT;FAE-jIl7?`+m!lcVJY-mrjFF2qulX_m_2QFlaa#8$*@Pet?(q$tt(j&k$~mF zOO|2vfG)U?-no}0?Mjx;Kc zmz?rQY+u1NiU2(nA|9v{u>n*Pmm5L++#+Hqplk9{&Pm4RB+wZCpaiCb$SpSw%X zA87FjG2&(a+nE|N?oD!IiHE$Rgxvj-?%3=U!q1s$f168jUYW2v*7H>Zg*Ub@z($rI zL|zdX3Uu%PD&)NGfb9k)7NKKc86P1qFyd>4t(MClnn^3U0Y4=gn@+IO2dkVxh6aR= zfG5M)huG9MQL1>D>6@Y(y;8OM-jViFbP)e6mA&_Gj^aBAZH~*>!81JPivp`Eb`#Ex zW7|Rl(lQ#JN_jyjU^*tHWVCTXSCQZZMb?ln^Or*&S-&fxZe)jo8O;Nm$i4Q*j|c!m zwGswECfRj5AjENDb=uerjX6;@C{Zn@QQB++0y~zAivYp#tg2FvSx&MS-NKPz;V@>60)F=zVyTWM^D4&!Ue}4P9d*tm(+o z^MW|w+Q4q{yXeOnVb^`SY80}hPr$IU^;#z^%Y}C$-agvs@H8Sm8<8SJd@kNUdAgl` zm32^^_UX2XzkmYS;D$)nTcD$V)nKWXLGA~YR6ufZ( zh3<(W9_%!IaQLqqYG;o+($ zb&q>fjbfhc8E%n6RAIHtVuc-cM?F|Qeq~#hMQ!!SH&K+uf%PJb*AfjZUJE>Szz|+x z@}TbHL63DnU#Ft1MdK+>k2BbKgG#43It$9v8lV`wRa=f(D|DP;Frw1()jmXvvsSVx zN&)Hi!|PzRB>vo$w#5~|o&Htj!Z&spSo^PN<$0NYG_P$~NQoG^VqTnOaKG&sDF+`d z<}F6-2Iu7z$@l$hwDHjWVW2N@50KLAah!^Z$o^|xi+=c`uBZm3ba!kAQ5Dff{Gc;BG)_7|EeE+B%Rzpa97Ocl{v8^IXA@1pwpwDc zSaiXDIiM}AZHvsp!cyI+u`J+_hX!m9kxGgjF#1N55mrD{Z&j-<_^qogEYmPZLSe4K z2@lDuFPXszHEpG)>P5|IprkW0ZgB{xq8k8S2aS$ht$YlD)n`ta3Mo0T0!IChQN#0b5MQsut#CgixHZ z*7_V>2zR_5G{6A}PO91jxG0p46Dix_mKr7ohYpVHBS=t_?F$g|M1(nZ|~k`xvt;#cz-o~rmyFp{y4Wk zyBJ>(k@5c*_a$(0Rb{?+tF`y+Nq3T)Hqf1@yOP?d zC7ni=N(cyoEUt_SLl_<+iiqRrjH2L-AdCy(4@6N%R2-ZqLS|gX8I-*L|J-}4tBXWM zhItJq=br65=X~co-*(Qub;k++X5`;>JMwGoY~1L0;hTQa8fho;xz`?%B5jeIevjy@ za^%~8K>Uwt{rC9cD+%Rac*TD(!cTl!1LH3~p13-{O;|sX+kT7Mt&yKI`fDZfuKz;( zfMPeUs>0-T5HpXazp3Kwn22ndcVznRNDFN$$nE-O4-G5H;*|<`C0509d!OnO zm8^}IMZwxAAMot3HtZBz%O_(4Cuz}%VvBQOlZsD9TbxV72C+F8j-+v?6dz5;l3AP! zUzX;jE!t;nPw$3cBi23Fki@mcJy+`s3f858QUb3}OI0^&@ScffZgz3cVBzhX^(wbL z@6uCEw|?>3Yu~c+L7ao!EHpU(LZDXOqJoiwy?7w<%r71xp}Dp-QW!r1c~At;;Y(Kd z@j%GPib~KJAlJPSUa5jigG4L4QZ)@6YvSa^`VTFpU8eGtE>oQY2mru!&+*8-7 zaKDLc&@HZ0VI1Tnu;%fi-l<0nMv5A^Y4k^Gs8B1oZ#~Y%EOAM|BQ9nMdF-2ZEz2ja zWo7N=7g`tXf3RHMJ#icz87MMq=MkEm68*D?{%EKdJipOW9oA?D#!=ugZ=;` z19}~>gu@t!04%!mDX1#kYt;FE9hF$zub>zb;IZBmD$we{S1~Y1Tp0kt6v+I+^RZ(9 zhjfn;y@uYu2-FQ)lBAX2m5e#Qogq^9Q7)JIvfPD2MS`(IUm%9f_w~>XriVSpZRO%v zaWEh*6Kd32A#iC>t2`k>DRc@*0ZbgKrZ`&04_4BfqF8g`d>~_weMM?n28&94HKE&H{HN*q5BeJ+7oEkE112tmZhA4*s4nOVU#1uK%UGS>gGVms@7qwH>{&o(S7d5^}#hVubB1$k%iKqYQ4f6U8z4Zd<+tQiX*TwP| zFBA;4>^%&aLgK{>rRw{d^CcOaX{tb=h1O=cOlg{1tMLd|1H8Yq8d%_n45WzN1I}NK zC$Vl1Ro3L2r6?1Z@yLnh19y-Rd`$Eb3ql)_61e&9{waGWe!EM{h=8smVAkC-V#}{<_EUU zrG(muS;Ni43yZU?QtQP?)SgeH2waq(DB=^5dV*-d+)8MHacPx2{)>u|B|-_Og$@@M z7E`?B@KKq5KoB{34tG5)3ceM`FWTc3c@>#-U?Cq9XvVIA?ExheC+g5Fu&wYm1nQDD zBwW?T^a%fmcyEDfIDl~0Bnz-}T2yE(uEcQF*dKGi9rX@yBO-a)WO1@!m0$_n z=n7I3y>Q-c_5lwHr!Q15&Oj)K2b;Z|KC~AY37{|NiqO&Ub_gKB1Ir^Gl@+iJpvFXq z1^k|n?_gveUqt04Y|#}Zp%2D9(m3hS^5S!@d~<0Db_nqXLx$Mkm<3oMTj)!I_fnMu z0^U#?+7Qq0fPbN0VZ|^i>fXXSvJ@;%Zwhyu9*%!FJ*jG3c3r8XBU}zWd9vRk zUCCi0tzXydxe_J79iP2dUfzt%YjF(?av6;=vBCSPJX{InXoL5oOtd<7Iqsq9>Xny6 zkXKc`c%AH%U|2sQRehz=$mh*uCa>qyx)F=%6Y>1Go<3w|M-%CZUB;NX+q|@3=JE&4 z$wWLE&u2}P<;-m((Q|WS(L_3D4n@a}RLV@)(NH{=GgGmlj1fI(=3_?Q$j6grx{%Lj zjZ|*b%;wWW=qPLEaz-*;NaZC-ic9s97x4h%D#WW1*C0kOgI42_L^^tqfO2^wnVHI8 z&wPw2o{Ohb<7RwpJij3wPsPksIw?s$z~G;Z;71_rYJ~E9_EU>chft3IE-1}Fn29h8 zp}g*Fq&LQM`D}cokVl8-70m2p%uJYLMn0V#I%Fi`m~c9qo657NYG!k%4)0K!h=267+5aXi>V(cSE>R_~x%cqk- z+rfBhELJvnWMwgKGh^h(<0H`tBbOBOu^0RYfT01_3y9r_{}r(Z@h=e*hyR6`Yvxkw zB^9w3G3#S(1Q?qfGU;p{B#}VJ4x!|vA=D+TQN+am`F46e#w!{diNugt!=a>^H%LSo zV=SHmDW$EoE#bbbY5&Ml9aeT%J! zDFB2s8}216Q9NbuS8Vt~DwgBcIm|J}&8(iA%z-!PW;UD7hIPQ1sntt!5IYqdU`~}T zl#~7j&>nl?GEkf@CT!CbfefM!X*P^5JkHHIX$kt;>e>bV@f;`tYV~ zc31~;3a022O$EKpMcmG%X(xvPgUYq%^0D?@Hrj3;Cbi`P*&OP87X2(i{8tEz%hKQ-ur&+O(cUMlwE@MNZ0`7_wSchNEjn#0=?wR zGR?zgw2(K?by<5ZfS9zl-%g)z$A5>I`|Li%x@2m~$`Z-Z`7+g+lMI$j`Oy)j={>azvM@+tR4`R;qxSdWPl%((CnK*Fj zIB;_r(5eZzseEn|g#Y9wK9b_04G7_8<|57$HmIl$IBi}^NJ;E*;*$KHbLM_-L@;z< zH{LqFp~f(Shk)u^Vkm9?%3F34tgPl-D*bjW(+*KT*fv5PJ0$YE85;~j&vHM zCL*&x+8gT_>FXNl4F!W8v97MsE+c5hjA(zi8Ej9)N3uqCvK=fX9TlvAGCDOzPVjz= z`5eIfH*`Xt7zK?})(wGcgu@oTbK$VV%COWHKiXikeM}!Kvida5P+K4;97a9yv^Hyw zCNQyZIGGy@hc}SNI%U&=5Z~x|Q|i$4COaomX4Yvky+|-qu`BI9u%Ys1IE?+8H%|%u zT7X_knK%@Y_+@77)O`(LdBDY;!s*bn0xNGCZzGW5*~xHty@=PI24=1> z0!5F*Mh9XSoTlRc*rKhjz>UzEfakRpL%fs^1INhJ^@=5GWs$@f@W8m_8ae6A;V8 z-fByyn2VVDb0Kvwm7YkI%G-2j1H12zA)UT=f};gsT&BXwABVe*{L^(dekFg zg-jwI1?f6ak#{-DsDoGbd&q!Jk;?1CD7(|HXXO{+@U$ z-_xbHwCF4KAJ}CtBPI@@W~8%v#>k4<$3XK*BY~quf34Vwu22BiS{TI>~wq99HZ7fDfp7muL4nu`&=NNUfDAm0%PkK88JfL!C+{# z9V|X(t~`)Sr&f|ntqcab10A9%G@fKSCX}09=yL>p?gw+nvEfr6fhG5>R%Xdz2ML{Z zx;cjyPRlN|Z@jj|MC zI<&l6D~%mG8XvQnP)--57|_qf{(?*pw5}U@Jz*NiNT*EQ-uKc0v=4E-W>yd;bVAqz zaWfVsW$9F`prFQcpe~rM$cYxRS%@25j7E~~M*AKy9?{7VcyZYjn3SX!QHNU5tB9#R zuR=`f-GZ1B6_s-MkxM}((J5{zv}WLeKx}C-)us*g39}b*xizpFX-c0%wnTmvnmMhf z7SO5CRxB%9x)Jp##q;Lj{73Oj3f);Q4^F|hr-_&{CKEG93Yez!Ld96hSyTpFUaPnI zamKy@W8;{FP{FzTouIBQWyA&3XF6TI8C5<~JPvR_mCN9rmRJKAgrjD(<2i^xqWDYI zj1IKrAKBUew3?wcOjk3u1F4Y{cVVs%2Fm7|gf0>17MbQ}ISu2s?5~nWG9b(`h>$;` zkGwgFSRszr0x!f7iH@NYp$nlKp*)`(>n~N&qEJHwJ4+Rk4nNyC!@}LYpgL}vw+uU; zH?!?vfbo2;-H1jDNy{X>6aDM~{0|_I1{}JzER{+VR3F{}j%1slmC{k_oM|zQ^@s`U zRHAGUWn{8W9Y=(gL>c7dln|Aq!*>1a5tHuUqA0PXAtXpg$QB_c%>S4vkZ~{ixDb8p zLRg7V$UzeXca;VD`d zM&bF>*~d0pR___y+=sTk2z0ZN-k5$H<_yQtl<55Eta|AZ^m93aj^Lyx@Jt5%mT3>7 z9-av}RkJA~x@mU3v=eau9z=2`;r}nF2bZJIDfIwzwbPE!chZiqr^ETr{9B89XLWV= z^!D|KSFK)Sw~}N<)m(0m*XOUQuBol7Z37&p5NC zb=mS2Z7T!q!B9u%pV{r(TP?DF!^TaUw`|>Z_Bq?n-LZ4mdAkP&_w3zw{sk8rBhi>S zIyN3Za4?Zfr8AdibNRxdiNlkZaqt!%R4dqLzCfH)r1g>b z*!1#II%wg5GZNG0l!UN>b_l0~K2<}H#m68R(8mujK7kL!#2o|wFa+^OzRtiu>K=UF zWg7|w=>Npk>iO21oCZfZcmn7c6!;lL-Dbd`yM*RRd7A4nxP8^e-C^CDXOcQHmvY3k z)MhN9K7hjon8o36&O|{W&pdeS@?h0DGpA3c3wTQD1+0CkYSv7GF{37&xkfCYZ%>1r z<4gdCtiHv}3+^uTa?9D81FF(VQ2{+UD)xk#NPrj}N`}r(r8}9XizlEDAm&=83((0S z46;}V>tWP@+lpi2Ok#0L0koiB6Z6VXn2<6CW|>-P9)^)b1s(@Y@Df>`A{wsNr~>+K zp6#IOM4K~Bg3OxGrC=OzG$ZD?aVX9)U?}A?3h0Ar9nM;~Nb;hwm|;GfE{r5h9RiM& zm}=7}U|8hS8J(spCzZ`k>TsI~;Bk7+;U$YhhMG(CeWpH+0a1~|$rqUSwt`dOy$}w znLLz%brU~qTIS)sjh694+06ZyPGOw(;=y7vU}V8}4x1^Rgv$y@&*_B>hid`TgNHZc zPm)g9a2$9`0gJ9WCr#au`b~M7<);}pe1cQ%`QawZJ)cH>x~}7?49J_{2xPgIQm8x`rV+v(l#eqeuQa45@dMvEQ31xZRQvSiF@Xe9}zm7N6Fyb<+u^h?=7 z9%;ja-xDW2^c@hK10LlMp+4POPCLpSwsYjHSW(c;uThUizoU+3;XZ|*eUg$B8w6to z2PpA7xR)Rt!+KD#rVtF%>c!R`bK2+PV>q5HK;D3Kv25E>PWkSXk7GgYA}N8gnNwrJ z@`zE1!=Dc1Q+_gVE$#NZ?cqWE7)d*C!0FN=6gzi{ayF1*!L0@KJF}Lgm(VxqZe#pV z9P}_Usb2;cPFUA;OJCWECOrBFilipwk%wS_*p6@%l@9f&!|1Fc1yP6lZwq3|O{*@| z4_Xaa^t4cT^!+F&KAd_&w2k8YKPE}EmHBtf?r(!FE-+^dk%j`s35S^l&T{Ru^E*+W z{H=sz^Dr1V9sgndDU?x%a>{syEbNbP$>dt2Lun`&i8U{yF7+1g63Z#$v{^6Qi6xMd zj&dF(T%R-^QHmMzI)lyRI>i{-394w5Wt zmea#()U(!Y{p5vMweqqxD05nt=hLPiuvgB+;#g3JxPb6qQJY~duL9t3i@7_}`ORDw zTo;Jhh}e@K?Xw@ZnuqPDjX>xCc%);%qM!19x$i9W+Vw4DZn02@E^TD(61YOTqWwCg z%kjk;>hsN(L+!_i-DvX?V)6qASAd(w zF|G-ZELLUu9H^^_qEswo#~p86CjnvF*w&++;1~`eTYJsfY*PFkmd-eVm`=d*HJuty zDi*g)WjKI@YCe^;w0az^(mVj$u*`s|bj-9}4TUM|!-0bS?nS?(*Uuy7&ik4jKZlrp zho2&*6Y~EeCZFOq#2Gh5qe*l*W`#X2dx1&z@a78z&fvVvh<&%%qc=u9v8Z6KiBbc?AD2SiDjk$_7L`Fl`8Oo(>zjF-rNxstG!) z#rjgdL)|uT6GW(RNh34WkXr4;I9ySdvPE}Pf;Pz$qd#aGou5tyE;@q6P#&j&un%BCyFm%C*$n(gZmYA*j)>7_T+UsoK!W zg`H~Rh5(Rj=)-v&M!+jJJj#O!JWvhPhbiNS|5z`ykxDRH+FEdlL^N!94{a06|DJj@w%6B_39sfiN3~ z4o|~#{(0Ob^L=%cqK+Jt{QnZ=n6#I#wuvw#Q!V z&KJ>N6yx|Ig0TAj!b=;a69M71$7R0^d1Jc?oN23Ni^g)HuVne=}_ItusBpQb*H{$feRua`>M{n!Cp- z|64q_RHSE=r9X#fLG^FVpZ_N53<}>U{5&AH!IkyWVT@rR0__JU9l$g3KrR8X| z4Gte%DnU`$@?r=_6r6M>3~A^FeULNs`Z&g&rCCMCp}a!pfjo!Kf-2A&;3>0wQ@IRa z4+6F`{%i2eb#v0BoAUX77-_DPQ~o!2<~sgw@dt;ySGU(oDfCNwjCAXy*WtOnB27AV z$~iwuxbn1KmcACx;fge6s8gSGPkcCO?u+vD`zz8PL>jKYQhlb^m8E%hTHgM)iZt=f z@~O3lYMnHA?*cxS{u~9EsCIZO=X+4WbRD zyE6vTy^i#C$S2M!VQ)ho?L!UWY=mpShU zIUtW~U0F{|g0EAcZXfE>ceEA=Uxe66uR)sfaW?{OYR+u{fpc}%lzeOt0{JV;_af{= zD6exq(&Wj^;~&?PxT7}2HVpd_E=ITnp*(*GX=m(HS7Z4C$ssd}vBQWnuqZHHZKogV z*LPWW7JhBd%Z+)skZ;(|OL1Hzu2%fXJHBEpXe!1`9KCTYqsctRQAD5g4aU%yj`-Dw zzcg(g!^jgd!g3W%D>G2G83$JMQPD?`Mfy$9jeQO|kuKoUBdka|Lpf7Op43W_pc!n} zqVoVRe8Arf;WY|srh8v_&V-M%tX6`#r>^D5GjR%8X>LW!Pj4x5d96a6R$1p+mQl7W z5Rjhew)Qv#Gv3(1$s4Y|jp`$`-r%PeZVH^O!8j1dgiKo%kt02ewmR_i8^qjyw7d96 z+8RgrIo5-J!w}}qbEwDak98e-j^p_N0{t>N|K90u^S2?=uh6e(^|!Y9FA}gFI!&P7 z#SRga)PB%FJ5UEYxCVVRqK=6mcJzc$BeO>+C!R}CZM|Wp;S9f=JPj_#3Uw3~`uqV{h(bL(})zjV6)6?72 z*VEq{><#sH^mg`k^>+96^!E1l_4fA#`$BykeVu(>ecgRMeZ75sef|9yVn4d?2k3q@ z>qnNstNX(3YcZp+zMK~p^|gAaUy_`8{|pPjy+#~6I7{L=g^)%#CF*Pi0DI%X*+-%X?!{jzeQs3HOKqL9(;Y z4cq!GdRmLPxda1OHEr6)ZI5Jo z2In|=niU{U)O!l;sMqp5in7E>FTisTf+VXhm)os)++L5b!QWIhzj{GUeQkA}RTjA6M?vKH>duo|HVT;Irg5LZhh~^AN;}>AARhJfBu&je|A#R z8fGjDb@hf<&rhP&_i z^23jQ?aAlAzxB2+een6zJ9Wp zy!2mwRJ%BpZdy2W#g(6W;Hob^G-vLj#hbV6*m?ei`!Bijs=s^mnP-1+;@^Lh&E1?Y zeDKUb`^O&m{KH>+^0^;2f%^i_3fE?T8-6iIRzp>7+5&f# zTKpu6+C%56#k;+$)jD;xr_Z~>b@XJzJa2o$N_9!ylDguJ+R+cqubO?``(5p>RUV~w zp0D`j=6rSWI}55^#gne$kE;LUcD2`cWdE$<-+PN+clqb7QvL2e?`ChcJ72X(y->Tr zSG;;&lYfqHyH8WOWGTbnxhAEhp)Km-FM&jz^5O1>QfJ-(qDexCC%@2soF|)RF&HU#iI+=P+gO@ z)VIjB!nIMWU0%G;y;NJOwR*d%c5FD(>zm{E&ReyqUyXWw!8!QwSffi`*QcH1YS;W8 zpJ$!kqE-8P)Ua!TN2~Vi+Sc1y)9DF#{YTE+ea;H+@;M96Y??LKw*wt)teNleySI8< ze1)p@YnQuMx%}?)+_I})bro+IS+v#bFWz%W^QJ1lyJlwC?eA&R<`(~9b!?z|tIxlA zQ{z_eK+QIfzxdnD{)Ot6ZM|x(*YEE4_>c6=_pDNz_R4h~HCKORv`|(2>bti`YmNo$ z=iGeX(JjaS;b^~SxwhYZrhl`))iv|zr!O+k(fU0N>qrtG`knXKcb5C^dg(}KoxIRp zt9g&yc)fPeRipYm_3s_t;>)it{??!KW@c}`j9X!!Z+`JzN4BWftgoAWY}aD9yZG!1 z*V-j=W~I77Q;w`#+z@ujN1j@K^k0krxoo@U*OaRpHf~>2{KwU9S=-}k>{5=@wrR2I zz5e2-`WDu-X+G=-ck#nle^+ZzYt#vC2){om*HvqMm|Uy3dB>5#>V+6fkGB?8eV*di z&+s2}pO%N)ynKj`&6uk%uGWVazuI=^iseDQEq%`mZOXmF zD;K>s9FShud+sQW3HhoEr3_5+ zl~7m|{3ma%3eK*VO>jF!k+pZoiyAMg3j2KWJWck2Ik;A+tG&zT$$BpuXkKtNk6&3R zhuK{7qKaQxAS+5gxQM2Ji^_`>{OlXkE>w_bDRaPMP#dtlvPbnRi{w>kTaA{j01v3D z3oOW^R0*gY5;|3wZc_R&KBt$3@>W^HgB#%D87LG42!8meKhqTHs+HL`~ts>);QB>A6~Na}m! zVO?^^6$w9-tSh?|XaN}ee8nYyNLetWMn2O!zbc>xF*ikNkv9PI3O+>QmD}Y`K*eXN zFz@AxSAK>J}^IR@49x4n+#JchA940Oc|_Isnc= zZR|?Mx6G6-my1ubyH0|@ljO6s^N=qEl(|r*ac$e{RXmHd_p4H`*5Q?FM!_ICj9>3MDm$((Dfhwb{MPs{ zB`F1|9yKWCzNrh>mR-5&_>IbV@0Rca6_Vu2c6i1wH5#AZlBl&?{9^sm+AaJys$o#@ zJ5kkJ)OauUqlRw1a=P}@OR`%WOtq7JC!Nf%x#8ya)jxj4>@`^y5y>9O{ zNvfY+d-(EK+;kuXc16FJ$+9$U@Hb6cS*mNBQvKJ@TCH}AqDISmpn@tL6D4EL6P#amEpV?@pH>R_*%{)z3x6a6K zP0M}zjwHQXlk)HzKQ_9y-=6hbFTdvHub6!eEnauSEB9V?!`|yePPeD+YhHcL%U;Fp z8`9?NH8)=Wnq+_4v>8m^n0BtZ{`yzEOfTM-PF#IW_3L-j)w9>!^s4J-uX*JaG&cJa zdgWtjzh1cKx*L9ivUOG2%UKu# zUUrR$@|D-U;)W|Opm^enE8v-{uDIrgtMjyX#TD0HbJdMk{PBrOGPw!9vApOJikJ6**C(=)*&;Qf(rvLPluXr$f z&CRcVdwOU3bLo51_op}9oxV5y^=$q7(w|R%A^k;OIg}nuZ+y+Kq<5w7N>EEW0r2kBnN7Mh7-t>3;`1|y~ zr{7EWWv@k8-1z?N=d<@^cV_R+-jn^G*>7d{X1|gBMRwzN(%;E`FFTTbDf?LV@$C1r zFJ@oPCcgFP>f_lTG_nQ)?deImWB0JLDJjyKEE%-39YwkY2H8=xXR^+qHJSG8ZrIf& zxmXX1Zhy)jcX?QJ%XIg!wJqzYtWk7#m*-xXB)uXnlM9oERV!Lvu@x(}tkp)*+FcHL znO0g=D|x80=OxxztH}G)-rcBHkx}~9>`W@=G*We+6sg{J1^1Qt*BEAhr#4FnA``G zYcPy{?qF!a29qx`7%){E3>2fmyuO(s;FxvNfOFuvK>NNuDgpw zm)w;{6OsLe$)vxpKFg23_DE7TnYFb-Cf5zR_E(RZ5Qzi%mSj@%s9z0{r0#}In;!8) zRy5%Ud)(w9d<3C1)H7v`qUnM|^9Hn=vx`RL2Kpewy!=$+6p^g#CCCO$YcO<>6b%QW z5rJqJgpHyRgpfF|1`!qZlugMJJ!m0I4D?a0VYB=)I&>yUwj~Lpp`EYs`@F;?j8z(q z&ssCdqz95rb6Sg%$sU`WFeulM>ECbc(0_XhWozaE zmDxOB|6I`jDrJZ>%`s*D$AylWtZ+`r%B265RGgJFpZs&Kaf-1zgs?f=G;D3p`;K`l zMYfJ+MAc3vP}-_qc^F8_?G!wm>@FYHkNe*NY`+a}eGMBe@KihMm?p#*bWGD^qkz!e zu%nCVm}b#omh5qdhe(^KV<>AB5apPTQ8m{wNXb|cnQJdc9mAulmE3wlSxCq5z;ujt zH>xFEnvQA08Bxc0PeI41Ma|@#ig70GvCU*#8l+h?`hN}gNtg9)5?ppO`nF_nyDo#< zMSF9$cG#FJgB$fJXgjZe9pln@9VuL?a%rxB=9bXh7MgX3D(7NoZkZ~#$Eb3C2|;af zBxUnexvCXyaZwA6Ic2R4+SV$1K5!9_s#d_8RWUU4z|d^njcQeBW)f(m>Ykngn$@Dv zJf~trvpo)~95lC34^3#F;Y&x3Bl-y|I}@sp|0|-+W&*Vh;nfVIR{!fJM*K%We((E$ z{qNSX-;B~EACWo2O^Qb%O=J!|1u};Wp;mhgd&_c*VxF>^DHbeNRdZ#L!?K|wV&7hl z%7RDrRz}J~52P%tyHPF7otm;p=O_!S6qJQ`A820>MEi4Ei?nZ#jrN-oF_KuTKnMb9 z4&gT?VVZRb(=3{jFzvY#rd^jXO_wmY=TX9J-820Ew;)HyHu}GrB9cs`Bg;1p`8AWx zNZ)cTV2o7CmU%b@N#C7258e7aw9)ujb#Lo251FjGed(TIV=*3Ru9OFwX7(-015Jr~ zRAuA=tTy8TEH(4mcqAT(tzZM~DO)m_^q?K7c2o-<_`{LGl$QDK@)M)qR%uRaW-#eN z#RH?(Mm)e{{1CTu9x8_G|J;<-U>p=il)p+-7$k)OeJEH$Kgtl zVC~jMh#M1(RGu~Da5c&YqfLtFYi!Og3m%u+E1n1f8xeuc1rhirjPYP`nh<##zs+J# z4C~D&gFq-Y+no0=6~^Qh=Rve*NP*2c(E(hg4R+Vzg%PfWU&pgydRtZq7XjH9CY!>` z4Vo$Mk~4vC+V5K}>{f5d9{#!>qR+!an>qnP`!u;F*(8${$D)Co%Rlo`e?Fxct6Md( z%fDokxJ*m56G8$;DA z^GmpqpAuNAieVT>Sq#G_9f^xi1P!R-So9P6OSK1z)z(4UO8cL+wmz5*pwaS9ilEek z8Si)}@1YZQ5Ieb3omez0y=m|RRCyS2+?XAlq1()E&*k>seD~l?uE+i94|01l+dWtl zo2p%J<^I+@bWxS7l=A9#?HA&NfEI4_xr_`U|IZp>@dGNH%F6B_n|wyE%o)#gx$l;n zCNZY$8CdA^Y!fjxAO8UxzYp^r!X-F8kO_xVuz2ibNcg8*Q}(T+i_fBkVb5FkS7ry( zAUvBKAok1swI<(am{X(s)hHllr8PF~ZDga00U+=PY+qtRX0pdJVRt5b)Fx&oJDDLz z`Ta;}btZc_lc3W-Wj2@)qNMQlOgFVqkuvHwA%*fAN7EM(eHu(4088M&0{PC{Brf}3 z$`R`t$;}(DjcS$+ZU)jB?$@Fll=*Eu7dK44P%a za3(ZGv^zVTwi(RITr-zVXU)tEpKW((NKQz9DJZi(!7vTAT=ycn$v5ZVVSBIGJf*0U z(_4gxH_K0f!MuDl+r2qUwxdZcB=JbLJ-a`fe7YvcUw{-*O!0;MVSk~}3qA*5lpkmv z57o5+bzdIZhUpdWtlGYZI|b|x=Vm~ahj}sW!w@qR2^p(KJ;N9Eo)6~++Bq7LSTgor z>w5}^q}*4dtJfMOY)STIMygF_)Oeih@I_M!^LQ&~mS+DyoM{LbPc_e+JhLMG@P>#J zf})OaZ0|+OA7(}>Q`f{_SH zi$Q9=TXh#ak7(E@C=dwga8+paE3~RMPpD0icrw_;-*%ZyuI*7YILChtHZ3AK#BGui z4VMy)ASKSRF}Rc%x|ArQl(1((NnM1!m(PDpRUk%tU_NUC1@iXRSW=W?pBSY1Pz*$I7e5w!%U4uqy#Z@rs|xs zv1d9@8woO^S$^s5K^m|^AVHxJY?+qCS+N((hd%!4H@6s%LdggUYk($t-UN%SJ(`=} z1hPU+oHN!0y-8M_6J$jbx(l+RIVdK!icM!JwEPxAO1q{86)SzA#t9dT#jJ4x z^oDVJ_()c4fOj^O8?GO)?lfrTh~xfQAb7)WQ$-v045wL<=@n=3THDQ+UB&8Mvl>T3 zzd87{@@S2~KaonlY)Otf&tNE(f1A9BHK;l{m%sB~s4(w8SVy#R{WHpoK1lxYBiI3y@m5u(!;u(g$sbUf?iTHS0k)M}*%OuCQv$DT;cCcm6WIfYm-tc)U zkFxCyWYhDCEoFxa8FNx>+C}rTvr}45+f+P**(shmcm~Y4da?=a^HO8-^q~73tU!Ys z0R`=FXD)H4WspivVwb3ELeefH5ff9ZMl^$B9%Rr=2F=J_;%!z;_6*Z;nkjqgdz@~> zIu-4q4hAXhq_m?YmjTLI?KH>RVJK}M$5>lbZm2n3=8zflK5mWK?|{V~8U`}X%Oka! z|5%v$BSEm4{wTi?>``^nEV?jDi_WGid3&$5;L72?)WzAo>0k)ygFqqo5Da0S#F1os zevlvKVd@Og9E=EUxh45X==reG9CVZpdXumoafh1*=Vd#h&L|8d^nh8Cz4D9l<>_dO zza1Hl=h@HmB>dW_gef5H_vp&(=R=`a_4uLC;~}T=R6YXgC$zXG)HOrkV6EB*LbZbt z(8ho@Tlxkc-as_ptK!i4oz{w@>3xQ#@&H8;^_}Uk6SU|%g1$Nsn@Cz3-r495#u(<6R$dknlqjVf&`++dR_Qn9){t9ER zuroK3$8_nsp1169%z`5s6l=v{cvMxBudQ_HJ~awKhQ?%x&_*_@7yyzK?TmD3U--k~ zK22A2sY&`pbZJWnDo&FkY3|xu(7LRmk>xFI zT5KJh1{{OoR3+BSzZJNRIp((^#Uk4v#gGKD+6q}tj%tR1E})IgGy$!w5}PB#;t@f* zZQ1?OzLVRsBf56CW%udIdeXhRPHoG~z&=d|b}_YUN_M{HZP>5Wvc%6+G<<@34pZ1J zPJ<4nOy4%So0K@bUMhLg%LQUGg$!GGGWsr3fPRU?=`p1^S!YI? z3ySTYd~&tM3FVy`X{35Y&AuK_8FD6NY}rh8FcFMfnD(G@!P_Z~;%rT)j{ng8=_MBsBwW>;`Km&4np&9X|HH4yhq{j*J%J==BJM1jDVJgrAZ2IGlZpI3RG zSE^6>I6gMljcW#8lUXLXQ>*l&Ug`1xXk#$J5T`^9UOnousyKA4aPZRuaxNRlxg?iF zNV;@*dceVp-GIC#G@T4K(lqTzqqFpUlc{U9yAiz}HI{4k3Kt$DnyNHbLu2nsTOlEH zsd{^68ml3wPj|fR*u&kIQ_XbgU@!@eme@lTAPTNuV-huQO}h%89dwy1GjVd#!>ab4 zAN}SFXwgJa@cXQRY*Z_NB6dDK>Z*M3Tpx~sd8?mBCUGw;6l>!6HWq!f5Hf56Dq0iq86-Uw;GR0LL0CR9a80&5xRA#Z;F?C6 z$sWqxf;f>QjKKAS`QUsl@6-WO`NK~d9LB!{ILKk_N=ZV4$>txJZ2o~sibtzZQGPtz z<;PaI9TQ@*DUh#cx{9nVbi{Q zA)T9hJU3}4&AxYb*b=GG657g_D$AqLU9)c?s88jC=jh=vBJjQ9Ic{!YI58-tXEG*& zWEv9bbs7?&r)5g2r#x}r;C>!Z1pW1|N?n?Miy z@$ivs7>39Xa9}n*IOvGwO-u(@OL7{MUlZ`$FaggB698Z~0U-V)uAn@Zjk`eEEb7sJ z$p$RW-vz%T>!P1GS5W&T?EB_?+U*GeND< zB@NWB8>lpSROzuk$)W~AE`5v+6Sh8)SgnC@I{m-28O1tVkZ>xb8Hmw_ZahI7y5S&( zX+Z+g5CfAI?iw|M5f*(bV{0J7-I5fV_!P#$HXY!<8e^F6&2kIGB43;~>P`aAH1$Q)|=n!JNdPhCB!P08YvfuSgl<5Gh;! zTUG#qNEvTMq-@DPnB<2<%H&HbNTH#e;j&;uMamYQV9w~!G}8xzy?W3|+QSz-hnj=y z!4Ig}Li`X>Q`BxA9|~4#Qcf}qU&j(K9RZG_7d$NB!o$MMhjc}GPtCL%KQO1MyA zF6J)0hR7R($Q$>8diSIl&i!HRN5a_e%?HlHAjKpXNWqR(o-`4%>qX0RLuR#57Y!a1 z1GKC!JVe<5F2!v6dy*z0j9L-DUZaj7T2nNRV{`Yq>U!yDT^JH#60#6sGYv-UIE;f0 zKz)|fRS17c{PeE?Lr4;gZxY9_&K(yjRy)V^ zgRYUb9*>K9EJ3IRa+e|!ZVPX4SG`kM`JWYRvheok( zFpZF!CfYcyXyY_+5^ZdllRU#~>kR$tcNJ$NEr-Q=p<~$N7vXjLF%ak@Kt6ABs0Ik4 z(H1oX5U`AOKTY>0BS%3~pooF?dEGzVdt@Py?nkgB<)+=m)5Nfeq|Q3OBTHw-@8DaO z3iNdC?qa>)f$OvFuGqdk@9a!Ga?dbW3y%wuvX;myIg$}dbyK$3c2}ADYNFKj_!678 z8RX?kRvE?BLYevs%cL6>wPh+1U1`72jQP?dtQ{9U7hZbY$P1fuSZ({xbg)g5azY{I zwUGE(gSAA>ket;|XtrUYiAoUl2!c45RI4GuHnj1XX@{7K4`V>hHUY%wyN3N3VZ6Aa z_+1NUZb=^VAfE9@Q!-6UYpg30AGI*}YRJpf8$DW~AYCoDhovP!p@(*ljb=;ifiX9W zF~F{)D3d?4+67nxjIE|$47zl%*(j~pFnAg$TL&g*(B|uTezs~X zP^>!4M1=#H80d+_Ro;~3;5Y*>wy@Cy3|rc=C9Y=%A(CF0u%>0J)Fw=}ydZh2es3xJ zH(!{%J!e(JSKlh_QAF*5{IRCa2~8EYJQkW_^rOWRMy8b#TNX)1D-uh~%CnTvt z(H*&y%7I+Nm_g3D6yA>pkeQ~Sn}u!WAY&d83VFmRrM$~ykfJfLbAsXmwsbzV)z*6EQCsR_ z3&cWliT%*9=!(c-8;XRzOLA|vvd1xgKeTQK>ZYhEVe24 zfUC(Uq#NmAcf9*ZQf{Vkq)UIWGwmt8G%xoxl(zI2X_{(RMzu9a=)#Is155zvP$dO= zf75OWKHWV|gSMkd`VA{m<>yjGhP@L0bl2f-hAVGePUnKDBF@;HBhQ} z65~oP$H)IIcu`DG#ll>`Scdl` zBNe83omDB___JM8ip0wh&*a%fByaZq0cEDXwB2_2%7Elth3#%iO#!UwjA3WF{r zNq)J~nz23Phq4fuDsNYIc1LriTOUl4^V9#}1z4c8BQ)ZISaiu^q+O4Z=8Bp&HRy(A zZOeA2q1C87E}9r)ZL3ecH3Ji)4cQP)VlWNB9JUqcqS|@MGgRpZZB3djJu}(410t#9 ze`D|SU=xkDX`mr}o69^z*!fuWxa)n|M9Q3$J!!Z`D71>^3leN$T#sauOLtqsMx3If z`NhN)AGXRiZJDfxzLcaZI@k0KLvYM+3!1Tny&OAG-cXoQn=r+(v(hJaXzgYs{xbJN z#Kg6{Dh^Y3NzpUTlVC{XW@i>Ej)*1NXvA#2SEU>YDbb_m5sI`6}bj*XCMiN=WjIQ>W;rfAF^;WTbae37x#OP zEUq#!OcBeg<$*KLB9@MbB@uKsfyO$tbS;jdScl@7Y_Hf|>n03$OLD!);=JVLx_^Zj zN&+oYs4XH@p*9|dP+OSV(L7)m$X(8)0{HidQ1rO`oZpxYZ9aQgam5}cj0yiFrA!6_ z8*oltEED4}{u=0k!D%tzjx$&yA1+iyP>ol`o(uDY36zu=akkq#ylxHzalK(G$&p|Y zAUO~dk{q!eMHwZwksN8199c>7g0>0gahtGj;3nV^nH$0D{5JYmQ;|egMU$kF*F^$> zlsky~%y$Y8pf}{LY#HWxCezZg8UqZnTN_EYn`+@$$*JG|YBfMRj4F!Tn>d*EqrIV>pHZ7M`^7}S}l4r+f_r#AW}^a*wK@AYKIop(-X1@AHDNm zxJ~%UG|Q@;v1Sr7HLiOq@_q`4+UL1{iwG|%Y<>*!w}=|#3PKGS0^>v{@^En>(I}$B ziW?_7Hv5_tX*6WuKlOq5S%x_9rpPNEX5dvUn zU(H}{vlv_?N*x5-fdUz(X5J{==WJ`k=>Z!)! zvcgO)XnadD81nqZK=S;Tu*4!k=C$#c8atDn6aBAA<>nh~S6O0xN5G&2ZBpZ0iK>gA zBJAJ1%oLAlq7$k5kd3YAHMd>sj{Cg4@WmFqNwA8!jIY$D43Q4sMBK zlF84UJ8Yk2Cho9>G?u@_9dHV~EoRBY9nu$20j`E6hu{#)z3H<*i%UGj0bjoVnUoP2 zCze&620#R#_XKa8-9CLIw_{nW>Y^xWGi^Ef!Q7=D6Ijdl?j6+OtU#I_UngeO<0nt zECFXE6LUv=lQt+G+PvrTwBiP)O$Z1-l0t4*SCmY1XAIJaeT~z-Kz1*&E_0LkG24-k z9E4Pz&2NBhaFH^?9#jc!duGmpR;4%;!BS};#@PL8A7SMx#vbN63#m*w zYZ~EU&Vsf~r1C#C6IFX%4M)Qek-|o4bQY`u8Zb8ta7V-HQ#)8Jl~ivsA`OR(|~rM|{grNEYd#n98h#R?Bbcktd7vv5wnGRx<Uze=87|p( z@)ARwBI3ao9QOLm-AE)rc=aP495YktnXJD}%dXp9L+?b2@@O^)vv@Y8kfni$q%7?Q7VZk zq61C7nVL2umzWHw;gl5);WPuMS%p(P*O)jAPI2ypQ^kBeV?@jDKBTxpKD`UxNBmj# zNXMqbdZwLWm<5B6-(~6!5v4E zvY?qAd-?;7oJ4wD%HQZ^>)rJ^kwnXo$<|7xw1WSUSH5GY{4(fk@jxy$X!i?tK0@8h zBNGG7^s;AZ7VWqjPv5--_ z25whHg=Z8Roa|q17=gDK(q+T7%q;OK=5h;L>a+=|tKUE3&~8Z}R?4V+Uh-mxJeIL} zc1!Zo!75!YL5Oj=2tb;HHUw%i;;k4Ki=Y*;CHSssSZO$(z`2Ywn zWku5ZS?~Q=cNeKUw$q2>&X6#J7B(C-iwP%;!ZbSmM%E!GDkVcqkiA1rW8hDp1NtyM zcteg)Lt=&pCC85yFD~=FgVU+)q8*Av7ZUwz?)3xiS{{N3j*p2(9G|@C7pF6U=J+5+ z8ZOcjscq75#FPZM;b{}YZmZJoYw6KW>oX`Zo#!2Jry-tCV_Yr}%kU1M>>lRDhV8i^ zW37m_YUKd1SXFdikRZZ~rk&1Eu3~A=BVm9x#SfhbnM>ZR_ZND*F;BFhs^Ts``~?iS zRbECcZK8Ui$q#>_fyD9`SibLu7jXW-ENd-wDD~Her}}3Ey?*#UR$B#T<#psaX2}T@noYT^LS)oN|41}ZOw>UhD_#z zS+PlHy+Lx&wmw#JunDo4Fhi+m+Xd?*F+W7~rWv)ztdz+3T7?}?Y7UKywQNDcj5(T? zTuVV9S7Af4pnE<|OA(+P_1!&R)u?HTdFhn;?j@fiT3UH~YnPbXM zX<)=}D&bB)(7_ZJX1mJ;qEeg?l9=Se#Mff3L772mk&uYpj)=yhv4KE@AuKdx_WkE) zXWZJfLmTtxak0gC$ckV*HsUC&1}0CHrGWpyrp!!Co$b)Cur(8e2&2B6ysS=)P*cI* zI$}$IzLVj8OHnAbT@MaDl2$&~N7IqhrPl97itEIPjEj;Ul`N{Y8J!qGzOruDaeF8y zwN5{fN+m}GoKEC>YV-QupFwo+jEGm&xbQJ)kUM_UkG&_-xznuR!`N^J-HcU?1@tjRxr_QuBNmA zYF#n2(M==eRI6zKla~)M=dl4ZH|3{&n0);Q@z~@6)RX&ztLEAAw!zAQ4k`W73nkqj zplKGP?^srJrfeS+16PpbFqvav6!Nd^6<@T^E+&@bFN9gFUZ9OBy(9$s8-cLqy-^=) zH7zi%)9c7#V-Ym+-t$G_)e>l=6eN{|?asNy}TOOTdig*6QeA!KGb^g#QuY(nvF;-D;iCCn&!0mN7F9&3Ol+*m7s zqU|5;AU+<>W!Bry1WOV=5yS{P6Iz-UJv(mVqcsvA9A(1+GHEkGeu%yOWG%^w21qoA z)pxl5`ERnr)r5y(###K>>;L$#zxBC$9ty%kCrQ+V2L`O#&JznDPuJScTy#v^zE^KK zh>mF!9kq5xq653b%t4?+bWBThXd^kIgVYGixgaUJW80E760mGLj5u~xQ;O)RXfw!8 zLkeNnS*!>b{3bja)0OaeS~#9YS}S12B0J(n3mk3E!SdN2KPz+!mTR~#NMwY)wBzq` zbb)7~7aK+??6&=NRY+w&2S%10ID313$XpJX&jiK-9M223FGuiwxhAGuS}2UQR8>oX zSn35!XmApXa_o3bjy+&tAaJcKCItFlny~(Y<5~@d!XWGr#d0XexFARKBqHA3$+O~0`LIbeX_x3nC)#zV!&$- zli!qC;0Vag@Hr_Q@Q;$v)LZZd`)@=n%tYKfuq7wd9LsmfO15d6p zZ?2ZzZy9p{er09h{HXMo8dl;QmfV?WGL)JSux6fBlX}=o_J*uXTQxDOh9yrnEyDBB zvLU4-tg4u0mT}c^ClZPNO1?W^?_6$GjVY4e8{$9P&NAE z0h(CDx`bu{wX$)PxPv!PRSN*gMT#~KE)qup%s`~X%(&trK^SIsD@BkycaUrwG-tpR zt4hvqV2!x^j?|-8tys`va}{Ky$7hzdpK;Zk$GF;Z=vQH5NFK1l#n93COrI}DF)@@a zWLV&hM1!KtG!vRL+FDbRxg?_Y;rxKZsz%{28vv(GLshWh8Z+AEdIX?N9vlkc*YL9Y zCkPUnM5xSlV30zl54^Xiy+=ZKU9moFFJ7k*$$Af|xfY+}fdtJRYzm}A>AfyskI<`W ztD_^>H@ZMw0#I6%l=DTKqsF$RhuUdMg1#FTJ^}}VQNsYswpy44qnojp1{+~V@W;~n z-Ni-=EZ_LL+lI!ckan)nQY7lqiF$|T1?kDUrnpn2DiNrunAf%x|AG(TBqxF>N##RR z$T=F@kmOv^quSQ0V7!?{#4?Zat5@#>QLkM&mAu=yJ-=7-j(6qLkrraIWESBp*Unbr zqBeCMRX1$~D#!|vvAiUM48PRTdc99(3Mt)c zm4k+aMDS($hr@=DTO6Tj0TlDWbcPamH5pX}<^j&cG7Rd5_MDX5k*sQBc!9vM&^s=t z48R}~loK1LlVgPpiqWw`v6IRP3mLjiNkLz9w^wFu`P?>A=2{J@ntUx-auKz!!cz$2 zSR3i6;=(e@$ORc?OEplZ$to-vO9+ZGswuZM9js<@+mcbM%3psyGO8V9lr354F(*+; zH?`(GMz%>t#f9@#ys0Ti@eom!Cu<|M!}YXf2_*-uhJ|vMOj=f<1%d>UOXAr8z($?A zV_}RAc9)yT;n7@C#31chAO>k`uMBd^t>+~;ex$i&xktGj10+vWG@0aCN;H|*5e4Fi zOFRR>%gtO{XiW9jO`zy(m`H-JaSD93;S;Kj(?1_GxTg(XPC=5aaFZ!^c#iFlt9Lw_ zLBt6MM1_eL47Q^Pe%2MI+)xYaie^_DJO~?`DeOv1cR=DA z-Js_j60u#BE|sm$D;B&mh*@#G8FB;s8pN512Js}F$y9h-Y6OijkXPL1V~R%b(6eI6rIQDLPA5b7X(Wy=VV-@MGN(r@3 zf5ntgR^KoaST?MZo@H04Ac13Ld6o5Se&Uufn|}kGpRo&YCQBG!#=@WO0B-|*4QDhJ%N7;(8h4?;87AL_I{Ljn@b zFa^zX$fs}wmiQsLW`iBen`Mdw5Tj9inmbEMVO+Mxmh4>T`N#}tfrMEG9Wp7l?vVhb5+*k@H^M=p6RcW0K<*!1d6&{%ShH&YP-Mw?-mSIzy`wW~2xlj)5ym!?bbf2yDJ($`W=I7-*W78}(b0`DS`-ipJq~rQn+=JQw zD;tm_(}otdB@BB)sXo48i z+d}iABa}LWu*V9$qvBb2B_v0Rf(FzKUl1_{;A{ex=xt-A&}n>df2vQ2Ao(+WJX2q91yRG`^D>B6HrxXk>X zvaK&s=s|}sQP{XfwRV2%lYjE_?|$U-zw!6Ub|%T*8jaSf+c#YFK;LkgQ$2pe#UAe# zj(l<(e2;T97dnO*q}P+#Evn*E#2!f&rCaP2B=HiFBk?2(v2BCg;wS00mBY)<$b1(} zRL8|846_Mzs8CeLuRv#%09X9foCDUekIOh{CIBTxk7`$bMKc`p!F`}nJeqK_LoreG zNcwgG#RpD|(yR&X$wRi$&|8$K;3yJP>yB?ma0!H^kFMEcs6(j?V}!*A*!1-glc(iv zxIGJ!&QH0Z*7LBZ&k0XE`nG33<#HK%VLa;h2@y;d2}WOTHF!q^!$#V>Zm&L)*e+SZ z{1CsHUh$;pfb@aLEvHC7RxdNLz0kjKBAcMvjA}SlLf1`<+3Y1}l_?ADX_mJe&6aJq zkz*~k-MG8IS)r>%@la6;Zy2QnNo8~2DDQtA@~Nfoo!DGsy9yT&o*HyXF~*1Unv2QRD<}N(}w8Tiu`8j(_XOJNdNuupQCk5Bkoi42JZF{ZtO z6p<@UbCQM=dDyWB)n;Gm z;c7-`|2Yoolpyu-+Dpa?ykws^Cr(&iAL|Fb~Z56erD%I z8b2Gm({{m`%R@?Hiz5-JFOy8oNYIi959U;;D2vkKYhU7SMhmkggGzAv=R=tf@?-5d z#Zzp~%*)Uk(q0-sEkUYFHk4?U8QAB6=R#N_Mqcuq zhA@x}mA)D~d6RYWO?+~i2l2S>Bn;c}G`wTqcE2z=*I!o-Qu!GPg$X9#4QaWuwCNwY z-fDqVptm>m8P5`3&bzibyKl*S;@7xsZAMPxxyWpfQ`xZZ8;1yUVL6CGKXW1S-h{D5 zy5kJAe8h-~S?DwH%7K9CH%MIN7!FIm!z?cQ4kq2Q??AFSBozB{l68oNO^fO%8Wdzv z(`Au<`D)YBK+^O~wqaSyshDamQ94t>8+HNL`Z(!@lN~(#TR^$!)dMly_PsACc`h=^o#mbvA(IcY|vBOtNL%XDI zZ_;s>;VY$F3+N}aco#n^$+TEM6%yw{Ur8p}p!8PzklyI~vc(t@Yu}fZWO~9MrnTVC zySfqkPl06mq$E?jl1wh2o*D@SY01sV(!^N8B*N?7LU$7wuP&n?y5%IoTU7%Kz-1Fx z`@BJvQSzOljCyZ;(C|BCXX<)IU6}h;rTMfR#%p0MGFMGbiZqCP$r~S zPca+K}0f5{7KKXv;u|{TI~AM>IP58-}lybga7H_t8ZFrJg`i zZFHiEWk#pP@h2pst>Q9`Kc$LI0_OP`ipnjDi$Mt{rd zzWJ6|-D+A$CVlO#bhRcDxJ;Vmh_|v*%wB@}TqZ4Lr5L#`LpVlUCMN$uAe|9GS_#jo z?s8x+DN#JTei;bOjxq?}{x%?7dnypB?s5?N!u%pK&zJU>fzX)miCAAN;abyUbC^&1 ze4YaN7s8RBeJU-5Z-^tKspfXV_lqMB%G;QV#I+KRygPa_;~Z)0`sQiPnaBq*&W;E+)f1>(L$sFpmO=Et$~9kdHUIPQny1jx zcw{^_6Fs1(!UqacQsF*%LQU=COCk-WJ}IzQ!a5N^SA~Agz^PeXO+#>ny6STpy1$@vS!mfNW`p3EXNC zTK6tM2!m3?hJY$l!ugAcL_cs)-}2 zu=0r;YoeMsTet(|7HSP)^OYj5vg|6l94CWd-mb(@Q`(}7`1fcIPf6r?%Hz^Y2}^3G zm5et6Xmj|)CSa_IB`07-uB5r_PsEj6iLY-~z+6|-jJ&ypw&pOm@P9T>^j&9X{aYt= z%7>EVblSbe_(}f5HuBX?R zkQSotjGoxZN7P9}wt+Q0#Z`A7WVz%@-D=61Di; zT0<6oqx^7{_eKkwX-unBEYoO}3c87Xzf+Bv2kd>bq8j_28SDGpP^F>uyiwQvs%sDu z;!`B2hhVZ!?bqS`q*<|M#~b7aDX$LzbjPZR5{5J_s8goJ9z$~cVp=>?i83@vNWa2Q zUcvZQ_7Wa{bX#>_Q z?@$I=4OA-ZDRZTf=|O`uG7WT4tMw0G`t*O{nDfM67!A^DTFRknD&=r)&0l&nvD2FL z*isIi&_GfD-v%0`U;6?D+XS?VYhziKWC?!Rh|e{O@x(dKHi|UEWEq{rOiLYmR3jh; zvZrim#Cp&MZlknOEz*>K6;7DZMg#^)np}DJ=(klGk)yR{SkMDuVNPo?@zNgGu+S#) zQm$GZ5zgD55X}&G?9syy^05fc0=tzXz&IY6%qitv8YY!&dD%ojuk=@D_1S*@$Uv?jA{Y7pM6WlkzYc#c7sPb+uOU)t*l&u4!zM0az<>N_kXo z-X@``Db<4(lVEU+YB8mMO6<6rQc@-UoZp;eF9NknVM@LGJ*7>l9%xGEv=*n-9@nOn z{Mbm?gb!7T=}?1WNnT!HG@1nKzlN;u%kUqVGyLOE?eNK`xf4~jljG#}aq#j1?nPKb zecX<{kMa0rRPg~+u~zSuBFZ-OF6nYZKAUDavbx_mSidtFtmE$*{+_|#GpR+k5od1u z4S6xOc*%N8zF$wz2Y%0X2&q}y0%z5D%>|* zH~PUFYfb*c3WLc}`CwhPqx?7J{YkO@HFpg=dtlE7dz?5$DY=Q0{*EN}MGzgFv@_w^ zzq#q|;kw&L)k_NZsC55r4738iSav7LU|-9OEklK+j34g6w6e5Ch`+c-~bondd?V7*op z#!z4{tmE|>bcPGG(uSS?=Jw+Bohh)N&hvCX{cq4^10Q2TsI0lP-qvNp1Oqzy{`Y_L zU5~W}r*j|vyLE7e!MO&Y=xUwdWcnS>b%OJZ;>_FFu^wib$(j!*FDwA32uLY7rwi6~ z2J5=w3;}tDfj&6hU=5RBtY^}T^%~&LlwmLfPJni%JPCCAY^h=14%!6yXa=2tsDOr2 zw-f=O2D#@lcevN13C$9Z{0;InxDkz0y0uW+M!sRVetSOSxf$#0sMfjc&0-@@Y@f|f z7ia19&Tx&PXggBBNzt00R$CV^(`$s?ymhN&1 z=U0;8@={ou%cZC&c8tkpZQ5)j6D|i~o$}6KJd*V9&rI`KDofV?-ApQnQ-)>)CFWP3 z-GN*$A7rqyKFFabmO?X)FfD(m;DUzguTGMwO!QOQ@vcLT9MG&xaE>35&mpN{%0J(* zx7_fm;i@vZgqBvpE}VlrS!VN|@A!8-pDNF}NhDUir{e*~+X?Tjs@|iuhQC#|Zz@}R zXM5E@biZ%k{rUtW`nQDJ__j+nfgc7_<#tDQ z`LKT6&+PPn+jd-Oq!m{B0B&3A$`o6bu9$m#0_K#L%Ew2yqv>U8nAD0ew8_I}mNI>1 z?s83s=C}WeOtxTCLR>^{KE*yP21~KO!@QI`Q&!AnG8~YB!1WG4K$*LJR#HmeH_Eq+ zdm*>sg_y=~$b%tWD^Wr&m9FIb7kn~yHy@W)`toXho^*9cUC!#M%e=b-gqZ=^b_23m zJ7u5r);Y)Q^QwcgfJ1b(5ZCZ?ix+a3E~-DL6)4ed7aXdqw`UirvRSU58h^$Sq0!gk zm3qp=Vt!~6vs0tRhHq&WTa`#>A6HX%08w)&HcA+bC(_m22?6Lyyl>5`PjrM7Ud|&x zhNN2(Wp)B2*}FDenJ{e?mV zJ6IFm8>L=mBlk|#Ea~@;@~lzqo0Ms!@PvIsF-(a0RSk8dJ3ru+sF?5#P~gOkYC`}x)545(h1foR;JH+8TOYgjp(hA=BE$1*S9^>$=otN*Zl z>L-+iPgzlB(yFga*f;6Dw%#+5Xl1WgS(CCJGmQY9Gm%d?N75$pfmWQz6G;_s;;RdE z6=sqiI~-alc$~Gk*i3T9JQHG%VJ)3F&m3?x0b6G@IdfS{)ryv8lCK!XijaW4%(UA~ z>cjQ5R;aM2?25JYV1lWz?nbp>t?z)I%{A8gM}7w<$tsOtves;3^*|Flr?oh-_Bc36 zIvJ@M{9cd(Yn#c^kotjx2dS9_CeL|x8T$%y{9Y_u`+l9y6V~nvh+@}34hGG|{f6wx zxJe@uR!PRKu&R9=2AEJzU3Y;gu^k=J1$Map#oy{EO*R zzIh*1q^L)Kk0ydpm#!pzYDD-O^>@RjCSoi8?&w9}W$T)$#s|lB#%0^H7s?mbmtxc= zy>rNUP>&br`=L^gS($tDIbxaw~~i!Br`&s8u$jh&ujeD|;Hv?6x;h05CC z(291nHWt@Wrh$Tv>O^VEqE{1VuBKfY1(ul0(_sEd2%nOU!ez87dtTx?3WIANH{sr~ z0+Vr&pUj;n!#J*g>_FVM1XME^du@y|-_qg5isx=Zr*N5(pTo6~_hmi~jqrPp5z)pd zMS<6LXtayA_KtPuT7%uXylb;kin#j~jtSSNz}RNNiq*&#!s0~UujoT)_-1k;Fw3Lw zjTOfj(Wlji(CC5rPwBzF3S@ZD=?m^PY71!aLdwVgOfi8z%Jaw{>TUyf*1Gg*M;@Z= z85EJC4s)6?7c^E>6IL-r59!>Ql!5}&fEKwsm%GC58r+?0>e`x@{VLR;n9Y>dK^WX= zgPz@m12<|PZR`3QtY40Qw9U7i4HM0ujA32 znPDTlo=7wXwZh}MZ-{SU+qN3bq{ocJ&%~=KZJ%F!Q7lAHrA`KXWr*h7vZ0d2+I@d~ zZk}~}?oPllpuoeG@@AIoZhi-G0n^*E6CPx#Te6v)gV6JLZ$qY^7E+z$*wfwBEG*c^ zr!e{G*n;bscD`H09Ge6*$+U%xkvI037Dd#^8(U(d%p4ZU8$U%9QvsIyx!2R%bnJ~L za=GNWoPOFAQIHm5?s~OJPZ>)F)VAyb-6`l{&g2WZSF75?Sbp@iG%ShdIYXWLexNIB zSxrlHWEnON<}VA(nD2JwiojIu<-rV@?2CaZv@eGb%O`O#|8IdAb2e56rY(hPikHOZ zl3=a~9Tk-0v*WpWtdnWFeGeA1Q*F&zVsM^6KFfk>FyY3N}m>Q&KMzCeeN4*kY6KyJtP!11{K-yikj=#>R6CSyR(W zgGM`g6YpVuAxc4<>{KyIo@0J<=)=Ontcd^1zDx#p(+ zEWfL@JSvUEgtZpd@_dncPHWLkRcA2*)Ikp-14>^?mk-to#(|53mampZ$r-2qk}>)5 zQc&XZqvkQPMzov55Ms>^N*NU4)lzbaoH^V)7(mG+96<@Lbw}2LG>1fDYFP*N7#84{ zM4|zT<$j#S_bW#_65^U(@3*_^y;4P*xS3K{f284%?aFmhE1_nf8UB~c|{PG%1 z7#@4dhJp@y&}25})Eainx9zLkqpsYeckn7DpVxpnr!guCq4Qkx(rI0@`bUZLbhdxT`A_-hG= zc&R)qA4+bB&)TK59=Yv@ ztEb#oPdUYhr~B^yYNL9rAJucHTF*cJx${QP`B6P5B%Nm%%LKdZ+~_~lN}|1yleE^Dm{6c#C5QBFZzbg&DN_pMF(Tl zG0O}!4THQV^A02O>&Ggl!J^zlni_?YkguCFg_1NfDs8}OU(#Bg z@Bz#>TB`+=MNc9?hq7$Dunv_VJgJbBlxgZFAnQ}%BseG;_qFfQ$Bu-x1(QPnvabU( zc|KXNDCNd^3`eqVYTw1x>*f8gGvfn4lb0{WUS4UNejEY7$PefTtK0~z*7^rI%*vAs zt#u&Q+;V>zcOHY4;uokRkUsT3Dp~rqDrv$DDhrBgCE4pqLBvW@c=x?uU75SivC6Sx z=H|AO2EhuCkXq&hKR7Zm9NGfLGa+?>^$lPy`dlx|Zia;{&&RS$I$)c5OwZ5%d zcKCy8fv`m@#U8P&mL2SO4LyU9{c8ffuno$TV8(CRYROCJp zjdB`~e4-7+<>LZu%Y7o&#o%9gJ&`6kpv-AnLJ7M&mXBx^3uk^If+-f(TcFg{)RN4J z%99kC&!d%^($*F+${t(b|a5KB*2iJk@-*G}v}d-!j}V z;bk=w`0uTY+3LCN?5@y=)IMHn6bnH^oZBW+nW-wLMRy@hSHpcjt>V6IaVn&`4l>QXSa-pQln_EDg3L zGb{t)h{e6F$l`vS=pvO}yD#!EigTh@Pt0^!32W9YhPrVe_iEluIV0lO{tx9t&>`Q% zTo@KOx62ZWP94r^bqKIIbjbSP5zY79HuA{yr5Z2?QwsuhZ&ALTrQKk5m478B)#9Nq zuLR#3*Flcsiu)P0_i>^%)}C#pHSbe?p_KbV9%KbAGq(6ko>?aBDD;g3s~|ZQBtVtl z+r;V`dM|bVkdH0!HtwLtK>)yy0+iQmwoddT^9#1;mljF+zMlj1AEq&o(|?}3;yd>6 z+fUw<-D-X(so)mxuO}B;ydMtc9f3pinf2s9dMc0OS@75j#bnGCwJ6r2kvyDAcXKV? zM98Y{ib{r=8yf7sToyuF{x_|~m=~%(kcJj(U+Q$x(SCewgp82I)rpzvyii*~f*zJS zz!T{i;CQ{4Kx9{x=lgPt?ljppDqE_hqx|5s!bwsM7OWS=}sxBNGgSQNmpVK%pPkF5V+OagyMJ{c5UeiW(C-h-H%sU z2mrJ>+pCX{EdA6h1y-vzS*K4Zb=y)Cm658{L?4UIr}8KGM#gu@oe!yrd>MUr`49XK zE2&l~taE70TFF~^Cbz9h`i$sbWVyw(hD}E)tvL?I^3W?4L4TIu5hJ0RVm=V11VMd< zrkW}ZXoyy*rex{nEJ*GIlS437GiIbiD%XyY%JmhgkQ0K^4d>$fQTI2RX>O#al#zH0 znq@@UY4Kjx7wSpkq8{ccIF59iVAG=3YGiSj^dT1HTze|Ib9F;jxN z4JXrk*lO_(&16*&eIa;W=!fgG8j#2D+}QDw4B8A2|IW3CuvIUOAXD=G>Ylgs}S!5<5DvL}#7G|ry8#ykrsNz$v~>i-eN}e z7KX2N#-4KPt@o)k9+Fnrj$P(z-Y3yS?AUtB*U!g3hek$U{2W@x0xO2Efo9P2BoNA2 z&=T$m0ypjdj3uckO+XHnVE7rBMsA_9Gi|i`6j}oqNs_R`&RIdwohWj1HaXxCb=TT= z&{zsZEb%=Rk(F)ecu$_D%Egqzu@pb08cs?Sux_deFD!3Tr*Uf|rPh8nRr~Ia-Raqq zwhvN^d{nx~e4rhBq?P0iby%#!Es*BiI@&2YL&-5CUG2t;d#5Rc@zVZBwF!@|Hs>?W zC~MWTF;Ejz3oL{IHaT%Af;9$U0QJxU04nVgRNlP#3pRLJ2sKhM9NVfRE$kQbAvRe z*jm}2dMo>7ozz;<+*Ityhv;j+KKcJCxBLfXbk&*VKRlJZ@{wQ8vyHd5b=uAm5=OKV z%11+bqSzlcR)KYo>7&i|2|z@^13kDezVby_xO(m%-uX`3g!h)@b3NtjAd=5ZKGSUi}Cr+t7ZV!X;*wAVPNx6G}SaO0VYC; zA4mp4TmK`ggb!D>{3JySmp$CpxcpO(-)L)xSNOA#I+#-?=pSZ(m+e<7^;Kjj{-4+* zOuo^eHMt%J7_cz7Pg%2AVmWQ4G6##MT=tUV=6{c(|I(#g+ z_FOVnIMrL9>y`bzvnChEi+TgA0)9Iqd<*|@1K*P!qynV5ixVHS@&st<1hjkww5Z_| z8mjb!2KgeA*abT**6AOo;qtgu`7F0vk_X#P5fo`=+rw69>(jJVGPzrlW8PYm>?@ib zOgnu}}P5Kw<;;KMS;CT7}F* zmppq0)UywyH%t5WpgjZpKF>HAvgP0(1=a}VC&Gx2h7n7Wc_-C(wAInYXVC(y+Sa*)&G*s*@>PIWV|sM=FYxq1m{7q zDmm7ZGPUn$XM=VI6@!a5hlZw&Mk7I7Ooii}{FB;cx_8h zrQQUMOnW1Iu|u)($pso=r9BahB7E7U&HyU~hmJVO!o*MLoowg8aU*w*4{K55t zy8Z|K)SeyMMmQXtT=UwT&WJ0)*u^<_nQJI+h(JLtLWI74n#$}$q73&ECbR6`7(5mV-JkhRAk2Ruj&(onz%Q2D(Usc&I{5*k*7QQYO(cfGEs4G>-+4` zU|LMQU;A$M+^3Q>LyWx}50M=DiSOM@P z`cxI5w`UIke!*_(V_oC?@)$3+`tS`H>FQhPChbDcT|3sI>Y2?e^o&C5`uhKVW4<__ z8wGx!$C?_@UZ$Fe5s+c%Hof3sMIf599J=vS$NC!u0IeF_#RzT;-K<;+Zj)C_p>$d; z{Nn_UpDPAaKuq5Y(#JH{$66y%_vw~v025H;7D%!W`7G?MRPIoZenGVhg z6KP^VpN0>Af)c8s-KOK-ny~q3dw`hOlH40a&7_#E{6Y}g)=v;JhpmJV@DgCzfuiFnSEav4eH(@lf*B?qUJoTHW-ut;`E&8Cay zX8A=_W2;!NLd0*vQ8i$x0KIp?bZ6VOAw+abgr!7t-$nDmTDKnv-5&IAkuBDV+6D~^ zHnxVwEI;YaT08G)4<;aIkaTB2(uApQ(jx~G63Se={A~b--6GZPCoKiA4p?)JyE|wO z1ns8?93E&78v#vkWGJri_B+JwGnL4H)1bXG84RF`b>J#aY1A@fs>~#%sWLwQ$53FC ziMl$o=cdm5Ipp4OyzK*;2*+!IL!;eS;mtd1n%z>aDdpFgO7m90zV#B-8Zo5-s1PeX z2E)W=ziSMmh93*;V$FJ^)6}3HD*+3kfdHJ;TVtf&RtayICZ^U9+yHCRcv6!T)tekf z=_WK*>qXc+O*;#WfY?`*AIbDoDvbkhh=17=S83#dXPgB?wS;VD8qg_XUQ;Em21j*d zgJKGy8-oUGQZOma0t!aDtL;dFjVtzyY#OfUu!-5>L|}xv4lC9fS6cMUq-g}Hrk*gX z%|OO}9Na~mYHb{r8Agc8wKyc&_?;(6wY7GK2Eg)k`P^7QiEQxqkp3H}Y%NsE1O;-k z<8lWJjQKGIa*_{}D+{UVIkc7uFFl zjhE<-6B>9>e)d;C^UN2Q`QE`AYIhN>ggCUn(+>2xep|MdJN7fU9nu%B5p%r2RflEq zixu1dtaZ``mK7I28`WJm_F>@CnT~Xans2qgcHh2zua*l%C@Lv9VYGjc5J3L}z5=Qs zj?jB#f|I$p-Z!DcI=hT(!}T)H&Q=;-vnYh@X0h(VM5lb&px3w}D^EasQFnc%CHDl6 zMzlB8m4}cin)E==zMWgF+LoQL`QL^}qM^xcc&A(mWbz6Y$r;54J8mH<&JYiYk?K6e zOJ?C<%tVIWXq`ASJ7tPK7G_`Lw1;cF@{PbN4;#EmkBkT@PB6A_-<7W`8h7vfUi!M7 z#qGB(q)X+Fbj&L$CLtDCLz1k>q|VLGScqNFVIH{SVl(Q#qBM4_OqhWjsEy#|O1nIWtje;qbpbV{z$mTCCVL%^9V-s5v$@B)BTc>_fkL? zM_R*nu$MjxYnF*ST=#lw`I)kp*ibf@&PTSA+m=&qTTTVHzbln$wvsU2ki9|-@|K%u z(_DXhZnly?2l;JRIER5G!tjwG9u9}m1RE0}Rk{BSx0SpV&|$r}DLPAM4V+waxDM5t z{SeK{n!#pP!;q_+uGZ)@HE735Mhyhu^qIesamI|I0h5Xbq!>w!nItLgs9@q7lL)fd3aw9gJ46FQ zK%l!oJ2*RPr#sdTLla#XFUe>}g`1-emdrcRtV>a7wk)V2xJQ4;t!~c3vhpXGODW=p zhXPQ6LGdGOgD>e86mG993TgN5;2a^xB0n7NNo}+&?}szGYwxFKadijgG=7K8`=%)V zA_Oj{FHAlS?JL;!X$3H0@eqz%CIsMqJ$^eCT#$_%f81{rhIQx@EoaXslCiFHqr)9s z-2Y0?$niJN9e9u(`-9zvR}HP0-L~KCHlsuD8Mdy69QJcc4?Uy(0%9u1p4eN&jVmtm z%iH~{94whQ;6-tWMaMJg@q)AOs^SGk#35|i)ySmnqi?_T$XuHe=>e`PUSL|=hg%3P zAFjm{;Bz}yK*--l^k9-ze-6n{rcfjM!-fiTFn zWFJ%4G7Tc;^9V;TbbuIZqdMk3Rse*)Ez)gq`m6+s(0?Kn-#6*;epKAXf>U*6Z(^{@ z*u)~#$t5UsE!(jqaABggRemMnoaVssgzj|-;@FcY&IUH&M2%IKevE2^h9&eD^scny z1CcbM8Vr#^rrH$v95tvVn0ZSR0G$9B=rw(=B_jJ+v!i`~4Y6-TXJ$df3BCIRdhy8N z!&1{_fp%L1wFo-~%wRQQQh|sT_WiLY=Y?Sx=jDlpChUJ#b4o5a(O~1Ntb&Hy8ZSs6WG{QHJ(E4$zyYS}BQod7YdeqU znyuBErUplQ+6gYJwK`+CT`d&YI?ZaKz?xpI)tL~4gNEba4QgANseR$*~{M}ymv9LHD3#(+M|e~wELcB-NgS6&{o%Gepa{y=8KKS~kcAIpXlvNU+Wd8k#y zS-+2}T@I5Q#smLCEN+|B1mGivrADcd%f!86a)w65?yq9x6>{ust*5qb->` zA;Tjtj{sN%>0^2yP>%QznV#55Wq5>jhqg=`YuR6MqoXbNH81b2HTh8+r5e3gjl!($ z7@V;-2&aK!s~7;fw<&;dy+PMemL+t(zlpx)dZdZV&GkOQAx>)dYRRE!%h(|7i7uZ~ zU}ma(=k0`7rhKu%!lCxKS58S3P0o2dZ?&KWl&A;dG#GJ=$woThWLUsyY1+ZeEGmS% zGBaa9;*OOm&(MP%q$vUn8;e!DrYv@4u!0{ZHaz2uZ9HcSP(b+Q{Y|rb&An!ft0+3+ zMF?a*6tNBZ=Zb)OSl7Hfi3hCn;67(RHz(g{;Nx>&-U&zMGn8*Lo+6TPK(FBQyhV>` zVZT@5_3gKApuBmuqjCTV9zxCxII5=_vIs@$3Nqzv8T?h-p^qa|A%62HaMow zOb8nqF1?u$d3g^L8;2+{o?$^7nrAD+ZbT?)&M(}tJ8Oo zCZ|IqHgntvQG&cYPO%O$s0vP40f(>0Hy*YEPWp}oC#_&+RPdM;Y#kMR&kD9%fz5n_ z%0t2vK7BLEpXJ+<-vdO2Ebir6-b0PNe4S6LrltI_mHbm~jabPCt>o`(CGWG6Z`Mlg zu#&IUO5S26Ul^5$l>Q>$p53N?_vz^jusDS>nfK<~lkXz+7592fSE%(-uAf-Z5_?x1@Lz#;eiyp(Ta zIp!d9SQON48rwMGAsG_8kQ?S8d(cp1Rq?mCQ)hkgaW%qjEIS%+jr`Wb}e}zDn}i zlw-q}fNP$)Ju~HK(q!6|<9@)2fV|NZId+l{4CNR*sg$ES!f9A)jk`QJo4a;TN^0GSTO)3cuGVSb|gsut#(wlLpySKOMR`BmPKyW+Mu-&>%eusGiv zYY5vzzIZPzZ4gRj+@@|Pumqqh3zL{fzRK~qz~a1HZBoN-qs;Nj-D_wLEiGX&l?&xX zmCJYXqN+7y%EFM#ZaIQpKj5OKvTOC%kLsJHLVawky!@bPt;ZXl7iiMeN^V14ux?_~ z^&TsEOReNSE4iaqa=(?luU7IYEBT^p8+E`3YP02vF1;6TPun={=px4LZ#wZlmIiGeYt%p^__HKvN>w?{IMd)lhMJXS z0u(FD1n6VTQ&hpQpEwv;}kI?C(mSnP83y+aq&q0fVec#qli3QMAIm zY@0&G1ID8jW~_za0G}PHq7|PG)NsrPR~cjkum}&PoJnkSWlkb`CWljGt zZR!K-&5eNm*zSMrDmp4 zB@yrR%2CsdTS41it>L5;r_!eIrq`GTe3tvQJ3yM`?dC3zx7+c_wTpjxdhnGb5cQ* zg{C7eS_bEX5-_AxuQTT_tJsHC$YLK}*9q$oVxYx7Y0(n%ve-vDhQ+>x3lsaY2`P(x zG_xbIk0r5lv5y#@%rQ0>3ou$Ed7}BG`~rLOE}WV zXy#`rQnf`nXhqn)Pt1tj%XhJ}Zkm6lPbIW%KBdlNQ`u0|CQM~!1lyR(cqgPujCDw( z>Ph;*`Q*+2X1lr|+f|k~Stgb@Pnf@k?ds7aZ=PtFOnB-xvt7Mtc{5f?<~|oCZ!TVx zyeaN#xy~dRd9#u0#4sSaT>1_Ny+P=^EBZzD^;PX^aKqcI2CrA?RTFZtDLV3}RmPJY z@!+#b;y4)+M^Ex6J>N#{%*&0nHojEqD)}aoAcwnFBT^aYWJ3OHQ3S(0rQVWV=0sdDxg(9bDX!pm+?M4-T?npQ~`VL#J|u*U=D z+ljEp{Bnq}4~GbQluM$GB}q-O_CA?KSc`c_-Ky}$zL)u$_(hf;VUzaU$zO^M@D?lN-A}UyP%}yv@ zl_hbd$Fh{4Er8<)$-gX+1rzEIuO0m5K)FbR7StsTE-3V`Ij~+<2!GyvE!(}e46=?| zD}#=#1(VG(*%g?tmk1thB(o2H%tpz{r?X^sjk=3CCbv|Q{}9{<9V7Ctt}MAx%InCI zrX-Ty+qRHvWv^V;j<=+Tb z$Lo^lcxAE}BE}wN2IO!&tm9S4dO9Lv+Hy$VuSLjfl87m0ClM3rO5(4=5{~FNpL|Wp zb76nelhby~TDHyQ#u_Ty=TdVf+vrMj_AqDcl9}wLvaK%WGw`LcSPrjDCQABi6J@es zPWhVb^<*d#V_&@Y^L!RazG2DBJjc_w1HK_mcxMboG13e5%=d$wSCfYB?c6UVT#k4x z?p(^joZwPSfN+Qf1!pffx0sq!z2Vi|3@gyLoq_SUSw_;UPHQ>6!p_RyuHIM_bO+jW zx=PMUaLooraLoor5Xu7IVQ6zUFy5a8zQc*QZ);%$kv6k1;>7F?uYDu#NRF7Sj_b$* z?Rd{2PTLzH;YQ1{syoI#ELlr8gE6~q#sI1v#tGevjL97#oy8Z1#t~|^`)1h8l{XJp zF`&&3uT(>zxdSPnslk3U28h9@snc^x1jBkza$_PDPV?CIJQ^4;tj?zFX|0RkV4YZl zi!uNr%Ec5(#fLG#UKOw33FEIK;#Qc@VD&E-UR&;>Qk1 zgXBhqTx_qADo$r}+;xT~)wmfn8GqB3F?t#|ZQ zzp@i>FD$ioEhLfM5!RW(H_>0ie7z$Y-D6=8FKaA6C7b*n$&~CO9&TRaQT_A($d^1!Zd$6oJ5=&OO03|oFa8xvbZ_wsIA%z1x443Q1w^uG zaBuP0%-Etqe2#G8Ye?>p2&tS7Uh1=&SXeSjW0hu|?RG{Ob~d(89<7FS#dxGqrE7Xf z_RbxCUzuiMBS#2;wi)%{e3>;QXE_1KgICMjUJCcs7Ab;zZeZvmPbRv+MNYMR8BhS7>+A~-@RlVya2T` zLyQhOH-rumWa0+sU{*f|R+BB0+pmv>GP{;955fBt?)$8z6ZhQ`Dt)*88$APeSWlJG zSYcl-8K(7*zb!#}Z*eF336claYGJ9}Gi{`raV`gfl7T~Tn((eMUK-OvZ%&K{e5W0p zG?(3M2hFVH9FR>4Z(aV)J5Yj^@VqG5Xr9o&^U6l^l8xpq8(l6HI@INX!g1i+wCK-- zVtvKUP*d{riKYmtA`6zUFX-ta@ep;S%=EdD38Tf%S*-~7)pSu7udpqelq$*boJ z}`?spatrhM|r=ne($k(I}Um5E5m7A#Biq(YWcGc~4DUo^ANXzQ> z_XaNB;_)#pTPxdY!$JXtg__sj8Lz*C*TJnVRBZxBy9}mPwIO{Is&*68s_Pq7ZAks# zmaeLO<=_?&3)GxcwVh=*7s+;xsGUXCUcDApv8}4j^2)0AZmZhzPJx+Fm+S=UsM=xz zNiFr&NmUz~e;G(XX_FA$hRfr{wzZ8avXt$l(VE85n%GhL0P<|dA+u5KMV{~iY=Sdget2bb}Qm2)b`;J%5z3!55?O)9N3{1>`fGEvC-*Jovi4h9!UQk zu7p0U!eQBGqhQM|!+xc5?Ko7&aNdEyx^rE22K<{5y`F(=pO;<})k31N=`{w{9^RJ! zrprQs>+=NOZl=qEC)Q=b8|$**i*;E_u{FBvdm>im-9b6G)nuCh+sU|Fd9H?-nkF<^ zFutS7LPxgOWTD7tt}~&|T5}aG3?jJ$TtsL*3+9m7HSiO@yK z*+w0m&AKQXs7wZxOKep}plMxni|?!KN+<;I!K{lqYc6!r2+ki~ z-qA%b-$ECaYSGa}?ObYC-?T1@`jU0gOLw4)UYx2Y8-n1As%Ocmql>zHb4-a#&39D2 z%g(3jU0~lk;d!PfJD?m^Q>D$j?Ag9`<2QlgFP)~xl%j!M5n7(r zFKKzCj}I?(qQL;EVQ?{8-es+php7d9uGR87`ka>d9nv%56s@8eg3`B%lzfb8--e8gsQ^Id z(xr?H2=YV#pzqmj+6@3?*NmL4cy%DzRUT8L!d+nWANiuWy-RZJ-#{a};LtxSanMwo zKv=-0rE(scotdsm6Y7NiMRZ;{lY{@Z3H?i4ax(NUsZ*PW{;fFluk2MR_)npKvz@rY zDnkEevx-M6*cWATnyuT0w+j6;;onK-hEsb4UDKyd) zrqt0$r9&p|&%_g$3lEc82_IZVtKBu;R;!h7DYb!ph23AS)BPn zdB{{43O&Q2L6Rq4?ij?}7nZ7=c@UIFoS$|t$uKG%N9m6t3N8+IF12^x#>FHQPin)o z#7F&!kn_cz<}ty2H1fclp~r6*g<+V5&88mXb8`MjK~-#e|E@vbGK++}f?Y zy{2vRPK)Yd`qmLr!0q`lN(^~v%F;bNM~dCM~qTWG)h(#;qxaWxY#9n$xAwzH|B3Do>>x}#9e8*IATy1D@~cJ!ccyP zXQB))k5Nq~oJNa0LuH;5i#PTTQ4ES66~D0f#^U2D48@lq40tcx@^h3ws_N&Ka@uKC zKkqBgcdoqPD=&1e+)Ejvs=jx*ed|77xvz8O0bhB*`y&Xg)T2&k_f*ePANpBU*qiLQ zAvz~uP;Zsn^=W-R2B20JsD7!pFy6P-rQN#5TRfvz);k4l?n$+W)>9#y@XAD{k;`oj z{t~r~TpHPd)>ZurQD3WmW`PX?+C)d{!f|6|ShmTKRefA@9_f-wfz(tU^ChQLj$Qe& zs*n1T(=Nxaj;B-*PkY}ecXAY$sDs5Nr*DqOzBDX#`!$}$g0ck)bED`(p;|tl%}#5I7@|wobMHd%*w(4q*cYbQ{V~O-zxY^^aUuK=1f%-dCIDR zv(QplNc?Up0B}EF2_>T2s&G!F>zTu74*Ozr|LrSR(^WcsPzBy7-~g7Tp_7y4)*kPR;JnRET|f`XB`@pUrwqB`?gmHna4 z`8AXkA_RGn$B($)n5$tQi=Wz=;5bE?X7^X4@8~rnOwP-xY6q^|m~?BEMU@)H*PJ%y zdr7yxQWY3o-${%i_v~xRA*6?AqF;@AoeC6m!jbzbygN~UkR&c<&86lM2b(6p!c`zk zqo>uVbm2C+jy6yy^NXoN44b#33h#+joB0t}$R|&9X~fhJ$w5|{kU_tXIorRZVK3IR z+JXQDTe|g99b4p*EQcn}WZELPRR7BQNlJMsg^qr4(T{#v7ggDrWIJkj$$7O@|6jVO zeF}hUkBhyI6_~*0_*k!puFb42c0RY#Q`znILshWu#k&0rH47!qEOtIZVjq}a_my}T zL-RM07!U(g3>6O-?^yajO!S!_U)~pw{00P~ll>~}TD`F3+ zl`Gn}y_p_!%&>6oRn!5k-is3E)-$ANB$Wa@0qaV88q_4-oDvI#h#l7k1&)*>kVNX6 z`E=CaqnG&=J$lTKE?=i*zs&>Ob^G8;f0>xA7*v|fwm+T5yZwoeXhfdam8+->Os`m_ zZU>ytB^ZyH5Nc+s`csk|5{NRN1^p?~pkdkR>RCc;Pz3m{=u_}et#9dD$Tx*}WTJ{{& z)#izW)9n+UildZ}OMHFZ^$O`cz0F+wkgqX9U4wNOw0C&f6+3GH(Tor|;0RR>W&Am# znZo$;td6i$S9!)L<0{Wc>aOyP!vkckRL(DCI8e9*}`PA)^{$g{$?&bVAS_do)oWL6_Ns@W#?}%M=d=V839DIl{L-ph3e=JCb9w%dD-SO>XA+-Qn={E* zfgb9j1hC7Rdq`-*h34!eXY2;%GEN56sf7@T>r-aK!EL{QbQ28dRANBEw_{_CBwrk} z3`~Q$x%#ND@WJNF5nrK0&6UHxLWi3xhkS(rHCNVs1#z&sa*l3;Gwl`4F%lOQ?cpX= zghs1FGF}m2p)=U26v?&$zBjK74PbLmNbM#M!L1e$e)}k8EAxIh)?2LOq&k~}W|uUC zcaNz{fm6l(4B{M=X9KnIW-~!;nDU)b8&#rTt3H+XgF3oIcq8WzE{!f1W9yQ_%-&zV z&H;EFKFbJ4(M4F&T16MV4H8|nTh20CqSn#HBMrUYJscz=rXuTxA>6Qm-myfhV*);) z)*mCuNqKu2c*iG6bubMW4(iRw%tC8pGz=O%dbN%xmqueXg|LL#hBe+1zn)1F-P6K- zymFL33yyPkO1k}el5Wq2bbCcdy1hJ0w`cqgQGZBt&nZC)?Tt%(`pnFDB}unm!3mOO z4vT$iFju%#omYzILZ3&wdXu6_65Nqpq%KT}wXW7|v33RvD59D60YJ2sfaZG^YrX5% zN{F>j)3My8XXKZm&riqLfOh^!Q!^qJ@$#N6QQ^{$M1@Q5l?6%cH2DROQjMPS_&Saw zw*homn0_&JNL7|sl306sA+Vlu+D0`>MI+sy8nbg)pj4F8R`~cA_)UQ452xM1@Pyn`JCCz#YhJR^gJ$T@YCD z1aa1eZ^Cdf0z-O2!efN_o+UhO0rhsX!ma-lo@NDnM@( zMbrr!1_ZD~I{5T=S|VQlPPbs-X8DN<{>e^xzCzC^#N86sDyeJc~PG$}f zYr58G&`j&bFSB__l*%R>Hz;Yh*z|_)nv(9YmUKt31B&7+xnnTEreioY0BZ2S&ssAV zww_Gbx`79Jp8@TXuz=9sS9k|gE8Zedj|0@KN^uh|jN(E}$OH2+vs8*k190trycE>x z@2r>4rzQA=z7HLW;8>bRp<9+&`s|8D4`twX1awmIA5BD%+N{#cFYge+-I)lIAH>fff&_KYqNB4I z_wkuV#s4X-f8-Y`RYp_&q~ePJc2s<*{m%6ImH;{~IqUT{qO=6iiM~mVK1x5cUjIoG z>%GO%=nNohBA;{7oRns4ulpu?Jy{-fywl_-Xi}t#t*q22)Tg7@gP~ck=f%zSdTfB$ z&J+9JkzT({V&m#uIV0EklxFXOIibU2BCVhO+!sEE0k;Qn+(d_$Vn3n7&qc#Mxy|J< zU(RIAD!+^6EO(ks9`og_CGk|(W8T%-l|`_L&Q5wXhJ>!p&gMZ|c+4mDbr;I%w}o=N z(*pCb7^%{sk?u%Y7bb#!S`~`1VUz|X^L&?d^Q>gsn0ZCbBKb-t_M_IR?&cy0g zhEA&&Z?C5lAc&SEjo4z~Hfp$hyqPldp)LUoaf!RuT16v9CG-kW8r5$QA~258u9O+W z%QEJRQMdtP?$-7SH`K9Fo=SshF!0t{=#MJBX}i} z5@`Kc(gjLf**=uW_6A9S#bKTGmDh&n zLK`N}csQpejL-^g=)m>nl~ zsJ<4L&?{HMTlbRb<*(9rcBYrZA|0g>9rHG49fjBW!n6H}HU?WMP{T2;O7ei6Fj4dS)0aGyGq z486}9-(Z-lTT`e{+ElQs{Z-!kR7s{N@QFL%la!z96W}5v@&A@M_-50fPE|4kTIK!U4ml zc2Yr%mm?ChryP-3J#j=zpzm|AKk_=MvgEF@5vov<)fy5}h^n!Jo0qWk13rOtZ9e8w z>Y*Q?RdH3Vq93?5T5|kw4qzuUPP9O&AE*yy3RKAY12RWa67u%UIQ;CewyDE+rG$n~ z>QF3+7RVRG!`}?f2o(rikv?6YZwL<2h#{mcVxDGTQ$t{m1r3eGyoPTtG!r=(=lfnzZ+urrjig|?!pK9oz$yY;*%<~=!v*wIdtpY+(&=uwYq zLOBDIfJuHab%@$BbO@%1Mg=86QIO= zpAz%l_MI?>{m=iW&;Ilu{`5b2^ts}_QyahE+t!z#+W4J(ZM72nzAtRr3a-(rW>2@e z+lp2+uARKmn@OvDVA{*Y`xe@|mAs>d;I_r(y~z)PK`*?c-u)f%V|IwX4+LD56f|2r zP`~gIl%)Akl1?nj-i39vemwTBlynN4Y77qma8^m`))3?UGzcqM8{WS>L0uAUYDY4) z3NqP;1ckK^iKS!-)^S5T3w5*vdwG(4S#;0Fd&M6u+Nb15opb!IpS7&_EV%xZx6R-Z zQaT^zQKCF}nwTX=AxX!xe|ghAlXZgmdEI*!oFCmbk`kA60CgAq-Y$;~d*{W;d49 zSnkI>1=qk__ZVM!Sb&0qbWQbXOM5B7Z(Fe?WE<_2W`Xx9?{Md&H-;EGUYhIchO3>* z@6FwWNm8)leXCDrk?SjkD%D?3)04%VBkCyA^i6_seq4in(2xFStn1B8O1I#VA75%_ z@~~!tnY>SSD`qm{$M*Da2^aV4+F{eqFdN>F5l1t1I1!PF3hCm%GUcC%-Bxx(?)QIe zJ@2;SdoizZId)qyy>~)ae!zPV2lZ(kQp{8`;94rzyfhA}?wr9bC+Ep#)R-seXvUDO zj06E^QBPZ&$URjeb+XikY)1d+W8C|l3g5K8vQaE=vc_C zM5?%1<{+O)9OOuFkckTECU&;7nycIa<#&a2mN`oxNghIH31N&@LWo&&M~=dUkZrB% znM**UY$?*Sk)fillvlh$7DZcVjc<6xC$eL`KZrrl7f}Lza&J*UT^TO&gM>U`ZAR=4 z!sh_AKxn!fh`W&F2$iRqkU1npf@mF-{z#Jkh1Q1*E_fK=LuQdM5JJUyg4O;Pbu@z2 zAood1%I4vqgq=s^m?7|9GJbHr*A6P=fi@gn;Y9(-?F^~0)c^la>pf?9AF`Qm%zBPa97tm z@Vuvy%ho5Mxs7NlxDh4j0M4|wTIzr*j>Bu5`X5psd8~$DY`ab9Yah8dodQwNA{+N!HV&-dk zlwV&IHx>ViYnlleXjp_*0Q(noRT)CrS^0&YSOJdpv^=tbQh1uebxhhUf7@N1S`rQP zmmq;4COgpL!i)t74(|OAq+BhdK@n_N!e_EfL^h`Dj8LA;bNH9kB<~xQ-wmfhZ zZm+K^hzoF=P|VO>mou3~A*7s1*`xb7nm|(xgo8EsQl&Xds3ql0X8F8*_Si{$GhthU znEHlMc3j?6n#FPy>dBqn@=(0{USA8bu8219x(KLkvi&X`!^rtWXBIxsEQp}6DTV+e zauRHE8^V6l?}y&~co6mzTw-aTYzh0L4PlSwPk5Ts4ye*}Qhdl#Z}a$&On|+~n~1M; zv9LFJ$R5%kdoVwI<;{6bLq z$=fd-l~3^@K|Rt(u2W%X$A@$Xdb$_!AtvYw*}QOqt{OF>i!YL(>*E(q(D8u1G6X%* zYKsL~xpmT#cW$CrM4mv@F}kM6lMYh>V3UkwL*$96{icj$XH4Wm*ufMVU{=K(>LVs3 zp@e=Sv4bON9bG&-C=v34(6#I!q7jK;u_QtS3rOV%7TXVwc2@K!6OlNoe!LWXLV}J9 z5J7KVZgOvScDMuO`xBH8n*=6e4-BS_tXxVw_>kWYVt-!{`*kh>y+bXrzXza29L%~K zRz`&M1VvQ7XhMIO<2>o0T`pMhd6MDK9fq**@=O+k# z`iKerF1bTGgg)JS(S%;9&#yG0w-+>~twU~K2FZO3ogvxA{ul|pS=)AUzvRWO2)%L` zEaPt?|AT2=x&JgPDa-v|sY32Qoz~IC6ME$)hUupz^cvAxwH2X1(^=79OGM&~`XLv$ zjULgGJd{hAsD`sFbZV8D6U*?jPCDIN#0Ek2&+)=17`nJ9c0Z(-J|DA*AI=c#8h;%aP0b|#1u7)LgmsN$ip;JLypR0;s z$XHh16p5ax~4JliqR{`@C51r6iQInV8*Xf!Owr#h4R1twJnHEXn**jAJBWn=ky z437V+PBIV=Ggi2vuu{^eRh|%W-;` ztrToEk4}%5+C!G)vULP6HknN#cx?hW)@kymJX|$;%mdx%B#z8nUQ8Wg(EQwxnG0x~ znQLe9)|t7Cl2qCGvyjf)t}wLDp031OAWlRY&kH2to_l6zGs#qSRSw z**=YN(+$V2&+BmLOh=zZC`_ z51XgK57-goE=P@79(#kKK+!blP8;GtsSO-hxefbXXoI<)V=Ibyxi!8frz{`LhQp1C ztvG`)>#9UpFwAXSq#@R9^8g)a19%m?i-l~3S&0Cbxs_e2Zsbn#!7P%sp?uV?Fjr3_X_|1>>^WPwJMP^SlnTKIXpUJ$tuDAlA#~_ zv7!%>Bdu$m4>9RqD?fJw6MBr!Z_b3&6cGrwg|OqdT^WRpq%BDyzX9Uc&Q#HKt8C&Eq@@QUgOz& zY&m>^_21L`T~Oikv+G`NC_uZQu zSnH`u#S4q<@L{dtmFyh!r-Y{xiHKe`x3XYQh&v16U#sXWD7RM8S#KTD`EeR#@p3aF)?fboSU%lh*1fA+1$by838GcKKuyhmM9g z6cG&{56W=Uq&fPb6M~uCIvAou#5a?OC{jmXiq?Y_E*cx5ml0-} zLoXx9lHyl{mA0XmIj}UyN|!8~FiJHuY2>K&zabJrki<*MqFp26E4(zU-?kw;78(I0VA+-}P&LO{_40|CfuXBkm9ID1kDWmWn3y(?0xm(0_J%0c(jw+)7 z%aN2Fxmogt1RF$XLRutxj4qSVw~6e$908Ua-8&PqvjZ%rWap(w|2@Y>P`R()(jJ-g z@EkK4R=<#)m)ii#AH$`DE}@J z9#o1fB}>`(dakg%R&uXB3;1ebvDsj`u;1Q#Oa=cuzf5(!!v{Z;SnF{ifg%u`hZJ^C{5*9}MGJcJ^Ri9paFuWXn4`VWHveNG z+M9Ah>icZ4?_|@}5BN$->6ZJTe$ZD^*0-;G%2zPdHtwE>eFaNx*5u?Ue_?LCAon?T zTBJnf=-n&ziWIbtF`w}IZ^;UcGPcfLS*IO>k9FE1_!!|7qA#b60)6VEoz?Kkv>J|1 zt%fl5E3E#us7M6}fO2y7{-F)l-)arkW1G=6)O#`Dmo~*;hZp~PbeYzgU(~PDd1K5k z>Nn`TvE>)_TXo);@{9U$a_-A|%5W{C-t)v;)R&Qk;J5(=S*R8_5Kxvp08m0a<5!>s z!(ZmW=n2lKd87zWL<~-162*e#83hOaB+Ao5+?cQq+6Hn7j+2oY&tGt422ICW2z&gI z4sv}0c(Y+?7mr4hF2nPJaFxASYUVk5SC&}1CxO)p`o8*JLJC+e(H&* z^;H5ilJ}7C&u)MQNiOs&B^j#~?Sn4mAZnG^_=7;jN|aqQ2Tz;wr8W;SOz(NjXFihF z(4na{MBW*AReJs4x}8U)#&tU{WGf|}%bz6WZn$9%e?RI81I)jDQ`zup4s56=OG?Tf$Nz;m&>JBH5uWizE=4GfwNn)rLC96>p zQ)EU`rJ`nu7H~Wh!jY(3qr)Z;#@>HP{A$UoXAn6d6UHQZFM&|Rd{LX?8m2-P^t1w9`2QyRC^E`aV_cRok};)QUE7i1TtULwW+sOF~XB1(0r zV5%UK8)Um*P2b)^8~!3^%w+F|Tc8FIE6A^<&YZwjl_P^FA7RHLzVjt`;FVm9Z0rEOfPT3IhPO6#jF3~qbFUm?6K{$rrwR~$nX(V^f+2*7WLs2|pD`s| zQ+feuF2w>MFnHG!%ww*xz}k21g)oN~zajyuHOGHZrwYE%-Xw~W*d!|AZO)jyh#VJ1 zMH~!SBw&**k!^CmBZ->9ia1FSY|AJ>uO`#;9cL3c@Unhx3@d6~EyINsr^DulIwEWq zHYvgCuo%cmH~uEFW5VLF`CHNwcU zhThgeRrbYd*+glJ+&iVVZI`ha3sHjpK{zI%#%!c(dt+RZG-x8Mtzz<0eP^uwckpSc z3Z|p}+J+#Qts^@XSdl_|8@jN0HP%k4BJo4u$RraLMXDEHo@brTYY!>PXI)UvBee$M zv&oWcWS#IiHQw^coX4rU0a~D$^=5B*z?~MeMkLV^ACa=;jXadV%1rakF^Ss0HZx2X z>ojZNQeq7h%gSl&Z?F+}&5YrO#)P{^p@E{JYid%tFE-tZCCNRh;zGS?8|`ZFh1J9t zoLlYm^{DOIEiL4G@UQ`B!B~<>bl5t+N8(p|i=n^H^n`(SwRL;zE3PZVidaz7*+9Es z1Fhvg_Fm17boO2iuAtplnd*+un+6D(%x|Txh;C$`H(Y^nvn85|p((0;-Vn#+^PVUw zv?8G-{M9px7*)9FY~Its9AL*z?>RZn*$yU(3axI^Nb-7j0zzA_w?YoJs3yGL3$lE) z_Sv}r9+~KkC}oz9ZFb>~v4cdVuuE(0YkMJ@+ogz4Vl_LA$J-Tx=Be%Yf?0DQZHL)iT+N{5-4AAmV4pjAyp5slFgpS_;P{xK zNtnf&ti2o>7k=a5PY(r?h;BCWiVLPEe!4l+!^1PV{Yk<%g$Cr02ghw#BQxzlLT36R zStP1TrmkeIh!}|iGP;Xrk%r|Yi!>&;EYjxqb{a*pF1l_{a_z=6vTk=YjV@v5l0ugM zDBWX$nE2{l=Fg^rF13klJh2>AAumN(T@u7w+ft__q*>sm+U&~z5vq!nDeuVDD-dUF zUSrNCDqOI7ZC*pHk$H^)z!J?2Rpp|Youro+le5#>*$&!Hpf9&}wn(T+B_49-kvEFl zJoAVyNV6rf8!fhzc@%rgfpxZvF@Pok$+C|uVF%4wYzbRtk=R9PhLxDw9q^t`U|+;V zdpYn?QM8uM$<&6xqIhfUvViom5Lgy3L|{QWD`im#mo$^A3$D;eRix~h&V?6WCV584 z`Eukq={qNv*(-DDmtd-Qmp}NLLd7ep>w$9zpL)RywdNC6_1O9kh$ZRCq#<%i=2Z^{ z@Jl@s&l>m_F-~ihci?9KQr`Nj^2C8RJaCmB82r^?PmxfiI5c)So_b3m1hb)r@Y|x+ zKsVE-I6Z(qHzq0G}Ns-rJh8oLbWm#^ti0m5{e2KKW-obhXdrS4MYpFnA_4+fj zbG%zX&tzhdb%y8Sr+ZJIP}S)Rxa%K|m{q<&dNw~G8+Ly3uj|KJrOL6g@@R~TZQ#;C zxfMl#D7`uOo2lKwUs_uF^{TAyW*$x#F%g9nO2)XKf^6#pm(i2isHl$|K3NPNuVQZW z7XekZNXB&Q;J7CszVljVUR8z3-IK)uu?KTs%yJZ>-+UFAn=S z@R_RKcX06eipdG9>r@-5xp-4;q&Fc9Zx9N-v3e_qihVfUFu&f)uNyeFZAXpWs-9|^ zmekW1cGf+X?Qyza-^eSNQ|dE1dHjAL^mBn3n0ka70xn~dHO|=J`7yeVD}LhwD{mjs zaqu$AybShnf)Uo(e5hnjAmN@!Rj5ww#N2{?YE$hL^>xucEnao|fl<|?8E$e5i)@1q zWgwfcW?Vxj;p58Zdwc%URc(vuORwvE$xaJ*?<%^k4-KwO1JKtyJ-*)U`1#b1yD~0C z{j@rC)EW%r<+NZVO?Q`WDKfIrK9(;bSC1v6<-@0*zV9R~VQ|K;bN;J3uiEo}r}Me? z{1T4$--5Kh*GWpH7Bk^2YT~BuP*+_ zG1OaIYR~AcKBx*O0qc5$ugdl&H_sUIQ;>tf6kH_(lps9p4_>Vc!>Ce+oe#`pyzJx} z`5m^-PB@id=@U*R8kuk^t?7I%=ZBPm1E^MD0Q1S3VCNAj*#i!oE%P+lHS?Ttpm!;g zmk!JJqLP`rmJE%f;PBv+LS&6nXZQ81nY$~|Yte}w1RENwCLy9U$@Kw6h;$iDANRB0 zLdLp&O_4b%LNS?60GZ{tUN+eK|TIP4m(${j(0?02^^(B9?zYj#C9Mb+`|Ki{` zc|xq=hJ)04TzD7NliAsdTkpkSr9H0LHDG2ao8IC(ul@90Fia|K<8gyb#{?G!2piFzK_- z%RQ>^`|OAR;Aj8sGymd074M-KIv^|Sqk2c_oTdQ+4DSG5y~7&eBWLtPZ}4{WuJizy z)nEFi_%9f^&Lqu%f@p@qOeRvuKEtvQxVVnjHvf7<^XrIVcNKSm-GBpcy^fa=1>VYm zb@L_;GXV09)zH5L+8g{!v#}O$zGFC(I3@@+BcQPaXW(X;Z*rpbJa`m(oq5Mhjpt>W zchJ#2y?r-Y;AMsc2RU#wg;13k2>vU$%b}@hm}8Hd!l|q!GE7`N z3yA4ks0=MmJ+60VHo>W%o*WRvL5zF#-&&n5s(z1J)%xI%|H#Q=SWR`d8On#7yH)$~ zW+*?A?>3$N23?8PI-N~}i`jUXci2^D;{y12RpiCk9^K{D#eQ#grl@9TXG^qSX8DI{ z!{C=VIl0Wr`U|>i@OLIB16T|956*n}?|t*(BR}_B(Av%nC76~l%KEFHd-T_5H@d>u$_ugN`rg+T0`nHbuvmSG#!Ew07~X zmr}cUdB^hSr^oW=|LYygJEq41XME|jzJJ}{R_p5@tY=woJ+!{r(E5tD>Oi^LE6NJP z`<5!3>JslhARTDSMMJt?6k6pIibLe~_e3#l~{m2$lW7=t>{Nb&ho zvu?qvc)k>0Hw5C+R-aLit_nEhclG7vE-1Frj752@jWy7S{#8|JNcf&V9Cici)G^ki z#pF+xjUv+o?gQ!nfZdl(L@WDk=8UG^~6CgMfM9yWu%5HC{m zq(1gf>1Z{0yJ=JIsO3aW6v`V*!3$g3<91J1sHQKwvGASK==IK*61^VUXe=~I(AFir zej+-;sY)_bq92=)ZWAhqtb4l^eUs?f(zoP5}ghH`1<0OJq%%kKDHJt-L}As?A}^+-E_OyYT=0E z3F!F~7YaRDF$w~)6Mt2Y-ymvJU<-+BTTiJClG7{2?PYW@1hA!R#WZuj^b=()-v+bWQ|^w$ch3 z{s*7?%uiCq6EuT<)}o#d{Rq!Vi(&}ZV7*&1`UP_sO5I%gvB^HB9#+Ifgc{rSu%d@% z4s8!BdT5(Y^Bq23<&QU=)W^GnU{_o1i&4)kjmlx>RYS3trO(ryecgX_XaU1TzntmK zRN9=ktba&@-zC*hB(THjn8C9CeGPe0cRQ@B(X79syIUFw?pMpwa2vflrMYioBsdyV zu~F~-o#~;lUfCK4W0>q6WsK!pLV)<9=IdAUX?JK@f3E+out1hGQG&AmWj!3HX&OGE z2g0PI2Yy=*Se+N1CqQMRK|W79b#p&~DvSyz)!^(7bm~t{4wiwk-&U`vN~6d9AE%jw zzVz$E`PA!gvR`HWQQdW~%i(md%K9JZZnERB>V_qsdQjJvSMX-y%d(4`fEQ-4}wStYd#{ZvE`)$0P23)^0H^j%+rBFM$;|LJe}!m z%sd@Kjjr}raWBm^%mgK&U>{8tza|4^X5TBM=V?Ph8}{&%^% zySw;*Q_o+f=Zj&33KQ$&Q+j901nSBA`>&jyu$c6Og@r~__`~1$!cVuF!vC%bwlRGt zn!=)uv=h2QYA)#tZF3!b5ma9SUE!$c&yID4ZJw?|SNPpatJ%Bf<*1T7ppQEM-<-T% zAiiwps=+pz;r6L2`LSxUuAap~R{wX@i{rTe9vt7NXKw60&57Q9N;fgQpGxOX>PTZx zr1Qtq{gXN>DZN*d?LPR)vdiW2Z#h~{looe-^%_h=)1y>!Avt!!cc>2al)YV>%xD899MY=qJbH9CcBTpVT$gX6n@x29+0xPadj9 ze0ooH9~CjVL7CJ2uCmq}F0c`<-sS_3=uJRC?a<4@OIpJJ_4BB`gSE1vdiA+dE~4=Q z-nsSl!$1FXzxwI3EArCuecfks-EzFR;pU#+(GsT}Pm#f>_gD1jk@Bwb>TuTI900joP0L{9=uAQwxj1%c`r^pMbDP?t^@VQX=trr zheEYVtoEU%Vb0gvlbC`xZ`R`RN-g3?(sz$nd{?nrfaF+7-K1WvjHrxS8r)&fNFK!% z0>M^E^COV9gHjK07o__3MJOVHTVkz6!5P#zVSv!j7J=pjY=FS~3*M+cG@iYds6FOwooz*joGk1={BL=cW)|OtT-S3} z(ZX<9mw6v_y7#~QAHVUHOZKmS?u)PIDdK2&n(o^3I#hYL{)fh8YW0IO%5T@U#lK61 zMxp=nz=!k${mg`cb!)=#tZz*b2FO7o3?f1S(jW|HN(cjv&pp+1;6C^$LO>FnU8l99m0DS2#?q)&j zmV1L3kTw-Qe6BHRdwTD_>#i}Y|9#YQ(dn(qgXzhcx~pxG5Qat02GRZv)V9g@c<8;l z_udcb<*WE{hkmTZ4|GF)%+oc{^&uZ4+;s!_84Py;_r)MPswap&&V)uxrRTz!CP#{+ zfMBp%{mf%ku3iZ>-UB_Naw-*7Wgz=*9%2^iM}TAfxPYn9q5AYuPDk}RKsI!TriwR= zmj#5C_l-*k(2(-N^mAdj`aU|f`X0ir2;QMR=2Fy>+~DCVc(WAUeW7fqB$Rp$;yBB* zXXB^o*6=XJgntT&#yXAKL<4TMjpE<%d?y}Bp>4ZrSADt&56+JRE5Pc ze@-2RC->JXpz}5ci~O*sH&71?G1-Cxc<36XY&q+Gat7}Akw!o)^{5Yybspg-=;=DA z>Au<|sAP?c&k_zmz>Z#G(Y+s`rSHIlTlGr;9fX{`vAQb`-_K#4@T50ZALJK@+x$G? zXm70U|3dkIcdu#+Klz~C=)R!T!dy9n;LRJKK!|{Q3 z4?8*!_3HmzklRTY7U@Z3+_>?-(}+@TvrKL7Ep|ITtXIjbL04X1Tz*p_i=J}&_ZC;W z_AF2FJ?<(7hv*O%4RS084L4HO1_uWJH$9`j%H^A-sF7odyO%M^M;nfhl!=Zpk?n67 zZT2`~xIVe*Q$BR zYrqjuD&a5z7)E`S-o{P`jSvvaWdl(WW6N9s38#P-0G^5ECK*IsuXYC#fjw1(r5T$P zO`}9;o(Zr=z^(j?TaI^z71-L?K)f~xP=g#Gou|11X|`@=aS7uVI^u=AL(q7tNWSy$ zz#kobGW8v#=H3QdSg221;RS}lLWVZQl-1RSmo=1Ez&rA`X+!UiKL()1uAIDkAeJ|oH5?G&D5c8(snmY8ucw|&{tI%)Ur!oZwr*bJ9Pe{1f@xoS!k8@6~e5`Pmpya^vJ@gJMugb}?KjuBk6uV%Q|aEnl9Rk0)a< z+1~PQp$k%2)9!n6LS9PKcDp%MyQfxs#p&99J@pN#fi@!eew_`h1icp!p>;f02JLvh z9QA+$SI$~N>7k{NV=*g;F<9(|GldOu`p8G`IT@BiQnQtqHw%F3sutt=xNd1j!fUze zYP4>GM&_cC3O_wCS=giztr;3wm}rFWNvl-0D2s};L&-r9d7$I0BF#NR@$_)}4pQx7 zDxHAWiv+y=1quY%@LsTs%GbbyP-M&h;`T&X?&(QsJj=cVBka|wKws98SNxE;Cn59c z1jTOLAMR>iKg;WP(h`Ekp^^q-1w_GmupVM=)1|(2$RawQ-P61C#vV0d_ER2axVpc3 z&$VhU#FHe5z@^~{aS{j-lbI9NP|^hr59?D%uLQ$eL=@@Pu&U?F8>yr%xLyM-YCGtDvU)ht@|SXXMp1%h#!dE?|8R6BIWRW?ZKf zV+$g5;bFRa_{NqD&+RM-#|6 z{zN=>2LoX3ITH=BscG}-JOe37*llK-NQ#`s;g?lIp`~TA~J@d;y`_F&vU;bY4UeP2u;7m?> z_0NbV$vbf^S51@L1dX`LcCV}y)V{Q7BZ($0O*8`NM3Y=XM{opdX0^aGo@lbUX7DX( z|L@6v!`^W24z^d=NT-G?@Ags#I`u>9^?W1aca ztucj}5*?|=4JCTOln8o+-r7*22YD5T@1HO+=z}y6HrU=lADDGRNBVa{5>qZxeB802z!Dw9gtUFfR-9yo65#8!iczq+D$=6-6LWvWDUGhA!}4TE}T z0Qw!lMPgv}4tSm$tKc-N5~4Cm_|ER9kXhOFsKmlrj@%zK(~O(3r;;tX~&w^RNP0Mq$}zi4IVe7 zk8;hz6*xZ*;ZcA-UXBqSkCb$tb+lp$330L+hK7G!cCDo!U#)iC-IIQGSf*}UY!F$p z>h$K$9%M;e+FM9~fjZ7$kLl##BBityOkewoSVgga!8xsYz=rWGx)=c-(qI!QKGv@F^5majzS4|NNvCU<&s zsb;Q~YV;MP8Y@V#+lM<5b*Yn@g+!Cv+p_FQXjrah?YB}_q>kodSRV|f>h{pFZquq+ zt3Hr5t6RmflVUY5SV5mqtg1rRuYUcg7{1~$l2$dJC76CL_8|#oJ|q~wPYYJfXn|!l zw@C|0e3_eQfsaXikv%w6s(Gdb=8LI_GG8cG^TKuuF=XXQ%tXeygS*jofPT=}z721sFYOgpm*2h(*>UWD9{_ zF}hTA=eE&h(DzHi;0dkzfS~Y};x_SLiX><>&q|8G0bhT(RIOu`TQ0QS{1$zDg(Q_BF`Cts;b`B8n+c*dk zVq7cD)>kXC5KnJ?^#K-NK&Vrug|EKPfC7YJor+xwD*y)gGbVC#PX*rLLJQ+_7bW@r z1R}Zus1eajBtWtWBHG4obYX27T^4n`EAx51xXkDB>Jf-EbIZOEcx;)Q!Dd|TSof7~ z%ZMAuD&QyBZQ`y0@uZq%5fz_cQourLQau`F#Mc=ne*^V5ImM9B9@&x8Q+g$I9(R*4nE z!x7R8Xyv>imTmiWVs`WQ_2d4 zha(Dej_!7XoME5Qj|O?%&`iV=cN$9Jd2K^@HYXa=#7}tIj8QIaBi(gtOz?|Bszd7b zj>Ge|c{*Xs*Q=doSG^=lpGoM;hU;vqKlr6bf07tUZ2oHndCLFs^MAk@EHM`E@sFjE z%7r-rMXlz}N_K;#nrIsIS+_xfu4&L(Wp{ozOv}YC(BP-3>1M@34nkgw1^VkH#ZHV+ zQV+)jjs@Mlhi^7ZqlSpz%MQWVXQeG%)SWfJKJX8eGL?@JG^E)>LhE8x3=-j(%Nf9PZ?12DBd5a!5;*WIfW0^A81ZsNT^{KMS6 zhPzF^z(3RT3L-|nXz)bT)&gY-q8!ybQ^D$=W5g2Ofcj~USNoJNbLleB z%aEV-kVf5H@LZ;hixNZPNyDlcJ6D}R70GT+5bvEgL0l|y`G5t@$*%_qbceS3%na{N zC5TJ$*inMGXhKf+O6~%~qUx0vqkV5{T+r(YSS-|p4uJ*=d=*-z+g)r4(zcoiL^=3d z*VM(*lSuB0w4%-ucDq}RA8(*cQ zzQp66#v?UP)tG?hUzw)0K;k7Lw{NFux-Zy{^=G=b)h4}V%2HR+Wz|)>xW8@ZVw?DM zX#zilrnU5g3TD6!4hoIpYrt#V7qOCmATL^>lb5v^?GP>mC_iT9u7vGHc^$g^(Q;|5 zs%T7tfG1=Qg9#v}f#8VE9U>PMS*iKR*Zi31gv=~Uza~iq6o&&+Va$X_Q(h6q_%3l< zLA1gjJBDHMum8?#;aB{w`|r{(mD1DM*T3?MbMLHs-ya(hXsk75Xs-fM@Wqw4%dR6q zz+w+2pVTFMtUSSyu@d?WmJI$kgGQ+Zd{#y>cbi@~okXia)wtB9qE^PpoeowM*JJJ- z;+iU`1rvUG4GZs|HY`vq%yIURAQRCEt-w|pYXw@A=P!79R%pdMoh~*h1!w4K)&`H1 zmGNwlV`m9~PH}-rWR-KJ2@i~U01^Hi(-4);G<951r85qybavtsig$fCzc^qhs4);Xi~e^BI4DDY%N)L&FF4xK_a8#SO& z8(NiI5Bu|F5zn@B>IO-M90zhEWfN6SK#GyVaz zC0DTT^&&y?<7&p4)t!!|cFOu*-Hm+Xpz-yuY1FO=*6G+pg5*)Xvsr@VkM^p56jD*0 zMqG^)zrdi90DP}(X=1)9d+?3u^k_{O&umI@c|EatMv^Q#Mu2t8MIise+;Hy3kfrqtr zz{BOJ6lv}#_{@mFsF0!9jh81C2_dHAxv*hN)bXMn&b7h&dhG@guWv1t%Oclu`MPo^ zQEG#qV-?xg#Br^9t8(ww_%`ZJq(a%<#F7<^G*wA=X0{MuW5&&Y=xFz>3R{-}y%Ivj&?HFIe-E~SR#;8HzH;6!vB z4ZO~Ie}I5ZrE?mNVdse2IU*mJRRs8qO+%!& zJCNlx*Hy$`DH>!LBB?7XCwhCG_J?6>102aK;HYB<(k&!9hQc=)Os~c@EBYcZ;@i?s zlZ(4Zlq3Gb%qwmsPoVO#6f=8^+K#0Vt~R%dIO#}O66@p&O|5H6l;M(1;YNo&uFV5JR|?170PYM?6Is(4C0vLA!)Bo@f;G>tvHwGhp&LUXa%#T?{hXMAQDG6!HkCV5P z_G7aEdi^FA!b-p}xif!swwi0>efr9V7v)z%8_R=3Uz8&B7~xnbMPABCek2$DmMqz< zCkzDtvCOL%BEqZdj_v0M0~e1xRBCewtwpu20yX}1KE4iACi%LC-dB_dfA4D|yvcvt z!CJ3Y1trR&+j%0@tv7B92IRN*~~bgLOX`HzY4J?)EL>q(xa0md|Pl z{723iR0t5fG}T%X1Mp36Y^`p@0B&0hNPtu(ySTnVC^~$evG%2dFg3;CD}L$L#9#1b zW5V&> zvSgPeZRjIC(ot{h4KyX!6SKt&uLId-WgGe#a8kEn1wkkXNdsqPB;b8IA;W_shQN`& z_Rj5#UX<^|GE3*ncq z%7JgkdszzNlW6MyhNWooUB*w5lq!BIh!U8+e{96Mb#Q&V049Iwsl(7Zak5^0RIjCI zPeH7wKIm_g4q@J-ERQ3i1MndNl6!~v&8n(`0^O_J8qSYY!N-VSXMIK-HfAXS#YChINcTr zy+nsBybT4fFT)#{Z1~J*#6wxml94qeH_!&jtyBc0JHlTAjWY{WC%8iBYjcGTaOGSR z8P!1N5Wge?pJqrT$!j}`-qRW$2{Gzm{WPKNXr|jn4>y zD-t8BeHukd#!6W|dS5_i)o3~ufh?&oN_MC*ZL$H;xhYIt%0bc_OdM}CH$w=N!P;aQ z45ghLd&i8|`jVYfieA+W6rbjvW{`%Iyd!zy%bYry&pE0_tcMvKLU(-`aKj$$RCWH6 zc^q7xfaWZosnKuH=(%W=54zDm;&g98Otsw*od$w!M*~V+aIe(B>88hS;J4k8wtNCDmLx?kiw(zM}Pdh^%x$V^ch4em22lgIahjhK#~=K0M}m@OYL?LV0c( z(HcN~V<8x*2g3SuV#d1hN8HfZbmJU1PU{WLlWzWY8Tu~#?s+`}^(KqW&k|SPNWZ_-0p`kQgLHI-%zxfla3;{o3J{2q+U@ z(SW*1rG*HKM)u;TB_U+;ACfKbUWQpeeUE;=pbnn&PxqhZk1(}I12;|!*oa;_<9JRZ z?ufJZL4=N2>#) zS@i8wm`4jlE}O+o1d&c{GS+)AuoOsF#3TzD#KXk(;Fg0Am(@Pmyl+4?aPfhX=WG%{ zGF>}hf_TzN`6Wzze_zpns(wJ78vmkVjcDe&Gv?$m&hIj4KF^m#TlkhGgbGr}rI8|R z?bI5V+;(i3YJZ%!k|lx!<(9mIjBE(JE6tD?>*Rl(ZQN)f+M>r7+Jc8~N&+vPzXC2^AbNc@5gm$9ND#CFmah5_`vZi7B{KQ_y^U-$Bl?Rp)vpZ_@oidk$d| zV(0rqCI%gF&1|4Ps|A~H)n_Tj?f)LV1_nAhQ=79iakju z7r+43UHM!vu(sKT(G#ZSMv1<=*7>UdMiCm%W=FQ19iAIqqw@#mM%U`eBXc8x;)w-!@>zHC3`JY?%o7V)vpBtAHbJ&T{iXPM z1wWsTpOOilil0M%vJW`(JbIN{cyeKcNvnQ3mNC+%+do%@Sy)_Ms)eMs&sP#n_ZCl7 z$hJt&$jHhtU?SABdc7U1KFgJJ9eD6bu5=)j;qiooDG=)nbTbo{)1slLQR?|#eHsSY z>Joy2bqQ%m=lW{&OvAbj*wd8kIV-J7)Jo)sR}jOLy2+Xg`Q2u0&Q#E*USu3LH5v^B ziNRY0nKQGNW|P+BkqS!7A;Rn72iJ>m0)&c``GidF#cZsLkv{WulWt0X1i;LLC4LF?X7RwUNUmd z2zE?evmnp<3RBlyIpZr#UB048dxE-8r`4&=CXHclGHFa@Oq!ezJDW6KVbT_vwD`wl zQD3GimBbxF>2gBL&w`d>rhAK%m6R^KEUfip#aELo#TTh3O`c@j<)lqMR@q%~oJ-8r zi3)`?@clEWmFeR&PNl_Y96Nwo(y3oOi#du+xw&5IY3^}))yB$hroWU=w$`c3krdDw zZ~be7Kf#1?nlxSs?71&Ll~mkg?uD$_(QXwethRWWPO0jM6ttOGnh4EJ8=pvRkUX9| z7qSa@2`IsfF+Q&)jR`z;Ksa0|eIK|$r0fR-A$<;lnoxl5ysE{rGQ%v)NSr}9)ncex z$HdJ_wPN`Tjk$f|K`45O23vZ55xo3D*?qw}i(V+X-Fbm#aKoO(cunXhyfU-7vr225 zTY@U-5b0B1hPhGG)-z7w&pj9Ed4ATkPzVim5?Pd8ycX&^;S&@5TZ$+3B*t+OD~YyG z>4@}tN=Fv(*Jf@i{*8avzcUkC@%}qb6BP*MILL`@;Pp?4aBUy~N4H$EG$ktbR*=O5 zBx0&pKj+n%NNQzLVir?9JL4s;jy?w^RYyf#HIQd@bYt}lf~LI)za?tR;6!yxh6 zw{;bbiFFdo;ggB{AFZ?yFhR!h!go=cd#(e+rUSW7HtjEj&L&!)i#} zM#p=B(Mz*Erz72YUPp#-HayYd1B17k=}@^~M&1N-CE=`EkiDS~E!fc7`R9{W&2}_5uwXjP+Z><#BOSc|y?VD4bNY zFdy-?HF_Qd;JKOT@Y$K@NlZP6-DOipJ8bGu2bVt5(CkAR(2i)fB*;v&F~TzWp_;8> zIT)`bB>h$?W}tssU+2oyIFE~F>(no@m{9ql+G0o`7MeUK*i`E;EF2i^Mo6EzV}#RC zl9Ey?b&5f^J~wk+l!L~J0 zf{B>|g_Y%#=zi~;p7F0HiI!#v=xGhhw%tcNPbklQz5=dNC61Y!&;w%pkai|~wY z5-a;Fsg2WW1Ei0Iofv}`8I$gsx2XeS3@aNMgYl!o7t9R@;~`GBWDEav zQ?~FRuWTt99%V1Fw}LJvjAX@Oi7*Y`ge^SQw@jdpKA=v~(Zf2z7Vgs#a*rs}u!SGf zwT6a&oHGsekd9|Sp3D}$mXPO6AYjQW5-T=g3x`tcTe1ab@uD<&NWxOFh37=TBx>pi zTY!+6O`NtAmY(+L$q;W%)xub{09*JiN`{|`0YZ<>7QWaQ`3<&k!tz_4(BZmpj|7G* z(Y*P0cl-);L7+?F4NrF#(lZGbPd5wc*HgUAtX6bdJ*WJ}uX|M`Z2H#8^sPi()C{j*#(TirT7C1%qv@3sEjr|wAwQkIg4)k3 z0fR@%;3UWWYK>!EOx&i5M*J<28cgSoMZ2rlK%*Hs&fwAf{%Z8v{l)0JfIv(Ve}jBN z-7%F7doUXn})GIOdDkfWtXi2!!?5p3n{)V2A6j zbat|lPmPPv*s}i8-#r;60AX4c7g>f(I|2ox_Y(ILp8#IpC4x=dmDHGXSoNVgjqls*4=SO_^*ZQL2{B znc3x639&$l`nS{vRTT52s}G1Zd(mJhD#DO?EL3dPf~WQEFu1)AIsqjHifLtJCum&{0$TJxns{wBChzV4IG5yjQ0pBpUGyw^P?K zR;57^`2SiJ9>naMXTH5jotO+zG=ZfItm~Gq0M`1~nHd&xm|~t-(3qq;oPSIp%~GAF z^g5NS$s-)Erm5(rkIymc$W?@N%(fDCQ(?>MF1WGSQB*V&m{a?vYI9&r@O+>Ky_kt{?W=Vee0i4zCTr>mdlfY<^qc z1!~*eb)77Cg~x_#e+CP2$UbLveC=>17s`4*G2(Xp26A~7G{chUjb_<_)BR;=mxlvR zC2B%gMk^3Zkqw$LVE$(_1Z|JNpA)bp>!leWb+ohKhEdzrC%4Gc(8B8HO zW|B4=7C%8_^2Ut9w*#<~H~L`--uOmOyGanI%c_Rsi@L+(ZF5o(Ru+o>c2K7~Ax;%J%H$OecTjEZJ`39ga4bj72 z4|d&D6vJ1GvKh(^d?7JjHITA%S~ZZi=R2z?F&Y3w%Vvz3QJFEe43=hPfZ8WmjyY+# zw$yL6dIkY(f5EC0$GUd>T5)CW>>?;>Wy{%(dZPuvSUG<$(}{f1guqw1HHl(F40trhQl6FY9+EClM4**k5~f5&0(qsNa~oq(_PtWTzq73okEyd$EjHV4c+yoCplfo=*C~4`>1#NHNWZ=LphA zWW%WF@tpzxD|DHmD}yvU#Chqo^!C`@#MXSVSmWi&;MYnN3x)-;RB$-51yk0=f7})B z2|cp4hjl=n1?|lk1tYF@+YTf^6F^QuF?0%H6Q5_cWKNUTq^bHFF=MyIj9EkCIUo%M zG?#n=D-Dnp0A;XYW$UNROPv9Pgw2Fty76c97UteB8inHV>=Q&H>EDRO3G%?qJw`OJ z!;vp&Y>tZ0#$g+y8oL#}3yYSF!;k1I9A%kOpP6)xm+jKTzBoRftl3YX^9np+9HzyF zE<>{)4CAm|=;aO%OywzS^bzHW!7t+x;L)qYrS5m4mRYpl1{*#f=0*4xAg=CWE$kX&9m z-xC11p#ea)+0Kc3rUkR6=fhn2I<>Vns)E!D=qH)q#$YSQnIa|?My_cejm!dvYTk5U zE)kyvjJAVnU#2f%e?)ONMJa5mof$6h3Oip&5TAo{k#{QrG)0jkLFBJo9baj(9Bs^O z?6mQs2`%zRerFVAgzzRQ7RffG*aUy14?`?gg^WcR-E5kUBuF{1 zNrja#$|OGODgF6S85e~vC%gfS#R=vHl`*76#N1hlxjZu^=CUD_v`p-{X}0MU)bTl? z9|98cYr+Lsj|zp9wX4czf5UfYs8o}r<)24gwF+k6}ur9R2eBs@RH&m=tmyqd3h zLwpLgrWH2n>m%xGX?pc&Pt;4Y_*(RBIq}}qoFs+LyoD^z>VOMd7S~(I;twTR zT#vW1_)%o>Z-LiZv;?wrW$~R%>4YF|p`wvL7{74&TYU-Qhx7@Kk}wol*APra#R#Pc zFX0v;5))AxwCEX&ws>2?ghE))kfinQZBU_nN=lZ-=Ox9UY}^1(p6Y=oT4sJZ@Ia?R z8y$r<92FZ}KlArb61mO^ND}EO$5S?=BP+P^M4O`%p)EC2or4b@-GaBVy&{v%aq@U_ zIHHW!Ifm46rF;kiXExS}A$9nG@^})|cpxHTV~&%9WFm%?R|an$eg_NXRSr12j9-`4 z4(Pt(f&#j)6DzsGZCptkSNYd93a7eOOV=jFV?>!Udo{S71M_7jeuR-86`+sWn0};% zL;WyUu5$0|WBj}_eje9zL>hblO#tWD4s~98f-B!0nLLm4^V)drBtNf-pZ7YGM`nSP z$)h<n%DN8M~K_b^${X+1VcsUEMS$=rsFeV zma=JzDdz)9>xsBhY(9`%NmOkvg^Pkz@US!s#8>*43WrF^RNhbO)Qro>EB&XrfQ+sD zpXMBGO<6$AIU=abN8$^^S~SC}oQH2r=V`n{GXW@Hw_DPd5g*%rMM}plJSzijKML6i zboiq8RD{KSa3}&lLw{uNP*N`}XGTV*(LB&O1$3N*4#R;K()3tzhlG#*;NG&;fRzJv z8$zn{p1l9)n5-g|@IyL&X3T-Qe4W z+2|aS#55D1vp+)Z)(jNIhQLs8WPr19)tKX!%)p@%cbzD2|!tk+5)en#v5fD>- zjL1Oy|JZx~AiK`yVrCKHbP0aEJ=%+28Sa`;>fb-l+!91 z{UOhEIxe856{{%9j7I`OT3%YPy|fs6+0Zs*GZknv_R?lzFs9q33|XK}H&DaaU`?k> zoAy91?SKx)fl}7)=lgx$_uO;$7XXT+4%UkJFw?%zD}PP=#WaoUE~cS6CAwxEqrQHLC}%fYx>knqfc zYI6q{uJn&XIBo_^BmgC&+(F15wjlIv<1*y4v0jefEc-&fJ|Wp2EEkMOP7HTWLSaNO zP`T<40Wqf1{3GAKzz2IK-|G|_J_uK3oR*^bq~Sg_)57RV4uTZ2V+MSuIDFjEpPkCe zLW0FZeD-(v|Dy{fGg#194NRhIfNynFj7rro2P$j(6Na)tb+h*F6WJrE0&GE12v%LA z2LQW%z#cpUyM6##dJ5|YCb$EK>fgp4Z553DMzVbPahcoh!HD?1Af-0;BkCO~w>}ON za4O>H|5lruX0$*M6i2;kBtp1ny&sX)gs3$UVNKqwWA{gsE(NiQ%!AvqzflNSh{qOE^9KB*h?vS8Nx*v zC4+jMa3K-d^_X~RQ|-;{wGpOa`R*%kKyJ0zamoXB0ZS;?qJ=diKOSHl&t%cULV%J9 zfTcHRN`+*ZuO$mo#*#&!AX)qt#X!8<2`iN5A`lHhH^r*qGIVf; zQVnh$yrAc0i=KrG49mjB$u$rzlJxw6k3w`ITw0R&2P9m86q{)gE{ywKP*qV27x&Iz zcuk2Rs)Jd$08+0%MaN%*9*2C%1D+ABR%CPz*+RNJ1WMZ73~LVA(yC?4oujzdKIeB) z5T>Gu@Mh`Xlvvq?SOG2_X$^n}#enh7^Fgqcj=6ql1I+99>FpIV*rYX$cdCT4r+gGo zEb!;X{2SIdnmI@+Q92v>cLYuGMwAUP%dDdra`4Kmqxm*WT8k0xAxr&6&@7=F4>3og}NlZIi5G?goUkF%`tD?B%Acq)$63eg3RX${Y<+l6v%a3Sc#>{qEuOq<>$P|k z_gabnFm*BucXDCyu0Q7reRoCLEmA{|oy<>~Q!|ZL-y5U6zM_5|I5eJR3`{+px>-n~ zWK*!Zx9harQ_5!;TNK!kg_|Q7_`*UJZ0`w0$$7noemC)6q>i4uO>fLo`` z>TI`5VbhXbKq<7)8MEmbpWXmTbGteK3&?5``g#HQT z8MDih>P6_Cp`4H(_}kJ9Wk5>j8%1Jt%AsPyvSae6B%%lOf_OaxL4K&sCXSXJ2#!^l z&|?Vs*KcM}HtLx{CWbWPyhh z{Y$&a?qLUfe68JMN9$iW%dTZ7i(;?r%wka!Hw*5h+}ILt#L(&o zi+<2Z1ajC9Fu`*XyQJY^`9VqrlD8~s+x{@WOI!8{fvBIvmVNd+<|pbjdm-5YP9L@5 zF@g#!4d4`u2mFTh9PY~AuEc)l(feTzt=sqN{7XJOHW>?pPa_2gv(EP94MCBxY&YpJ{43inE?JW#NoH;`C6AO3+^lK zL|(8B&{9w%4kTb7X8j}(g*}t`iJY)&p6p3t3;dLk*y4$MS0k|nbp^z=NeRlgEKP_a z&Ja)s<iq=inUYX)iy8 zi?cB^!n0f^DB@c~55Q*gb7DBHk{x zhi{HL?@*$c(oU)!xD3N1RZ67k7~5lXqNpEYWa5C)mYlK9&lF+1H%s*9dIZl*e(1xA zohY%a*u8|K+UB88{dK3#XHgaX*opWE5DD0T;EAnwD&ot=?@j0@8FI^Y8Dpv}*ee!6}@@r84TH}{3nLNJh z0lW&Ke=M}oJ`dmwNBNZ2ARuej#}bvq&~fSb0ARMdjRlW|%j7c7M*ZlrTlak?^pC@< ze_7nk@0&k!4}bThr)z&h&-(G}+}rQIM=$$}Dsq08UhUESD>HZN`9ALdqU}l+@44q5 z9U_`+NB#0a_J$K}GuVuTIX0xy(ZtFGZsu~x%U4@Y31|885~xB+OfHiiNj_xd2vs3Ouq44f->R+NG89yQvlx*NpYJQFX>qKoS z#knDAebASTid3;od*0V_R#pPPYcb14=J-;&7sr>vRLyj1TGU2(bDa8#wzl(SoeIfR zFWz`w{e&spJSsiU7!B9+1jHF@?4U}{jN?=6;ohujihSu(8JI7`bA3>}%21ntc;2}Q zF~D*UAENb893X!8=fTF4=ppM0`5VFWXzF3At`cZDTRyi^9w-lNt_I}h!)x+N%c6rO z^3;o)J8ZnHNa)vidRT|rgj8n_0ekJZV|4C-aCxK6`*q*2Cs%|ruW<{QZwg~!D8p87CnjVr6i2u)I> z{b5VMZ2l9hhhr@XaI-?v8eNZw zJ@F%}1=|;YpT<;TF}6=$O7-vDx^~i3N2Q`Y-5qU7#W|}km=D-j1`X^lWG%oD`o!tV zxy9WDj>M8kWMK$7HDaQ428CP;Wp&bc4Az1|nGS@t?oUYLj1LtW0a$4$g2}ir0Wk`X0k23(f6c2DBIQ2w^H4RT^w)aPCt>xv zQn&ueZ~WFj`tcW^{l$M<+{EPhD{BFh;?8%i7xfudke1;=qbc9DUt_LI5!0L(!>=}G zMBE3+FBBQc_zKfB=80A0&ZiL$i#WUI*#ck^rw%2}kTV`K(JhB#EzGtV2XRIWhvPE( z;3XHY0C$a&dMJ$Kmr;=Q0>P9D;^>g*Th~d=)p|lgWxrZto8bLWWpoPVM-&>^OK#V+ zQxmTQt9%k>5cv>JS64wM=(ak(pGqbO2A&AqmyTd&?xaqn51SxZEFq)b@qrS@)Cf2u z21-KIKv1xT5zzrAN2JT;Qn04XSkvB!HDeA_{!D#NK$~!=>S2B}$6l`lR}^KE=!SL= zRhNWB8BHcv`x&e=(scV!MZjiN#$lB+>{^@YbbI1NLKeo^L1`FXi&q3yl4EFENP53w zG36rWqej+>zRc`&!lvX2)w=2TFuF#QgJTVGT?fRkgtYwnpq;Xqi&vrp^>3kpT#zR&_>=0<9-gHaa-`>%s0CllTrX>HJM=xIZvE ze?XD{G^BIm$#qge6Bnv}PgB+({y!~ESkS9hCNjl8(xCX`6N)EBs(J;}xzf_yNTA_* zjjls9KM}nu$-<3~@A*MKhLHi_;T4H3_-qSIJdq@7x!~L+R?W{H(N%SxTGfI5#Ut(E z3$3}_-8+O`xg{8pe4*-$SBi$HYwk>I`V)DTG|%6jdm=Ho9XGKw(g!KpBg9!ha}!U& zcI7P(QTo)L7^k?Pu#BJQTTbjy;D^>Wtb^lOMH^HFEP76xsW^0I_y_*-dd_IhBRy-@ zXQbqrXJGiBZ5V8Pwa@dzW*N`Vf1bY5kb`~mRrSTg%n!nKctgAn8~%l@7%T#sP}LHf zjz0{XiLWL6D@gbo0#COqZ;)>Hfq_b9T6IWz3Q?+Mg4r1zFUI4G*St(t4b4lP$FAWo znFkxaZyzsjD(?)M^58a+E;p!f^xPI)J@OlFDxb4pI%&A^Nuy?7N%K+JW4IAS9(>mP z;0YWJ%M4VSq>x%#W2mXIZM^X<--R`0;s4@&Oy2W};5ey*l6NREsmVNS2gXYA;9oR> zH75RL%^TGt7-K0L+P)0%0;g8+gW=e*)uAPhtsH_kA6@98ZWL{p#`Hf47bF`7+t|xx zGa-yfIP(6zJ7-!xwpWr!%pDTE4V+fc44sQxBdZ*Uus(6!;US@tz8-$Brp3?xyI|W! ze;}o|RA5+%g}X9Eg=KSAEU-8HpTn_0P5*UhK%zGCaw+@_ka_(8uAe~eD#u|QCFW0! zEQ>6(+6SyO&@wbrx2!cVTJ}?~Yq%nru1q#LT~af9_<+`~PR+QBsTuctfsb|0vRfJM zr3nQ$=vj_;r}Q;Z$-bxr6>bdp%p`mjD9kwx2@r!XQhPZ|Fjy#dq(G-^kI4$?bDr4p?IwHa*AMR5cTx8 z6fwHWZAuYrZ#;g-a_qg%C)T+>K~J2+CpbnXoWo*v?dsUX@mq;`5O_OzB3JM-uHZFd zRCT|i+*A(wKi*v++bOGXwGw83kBSIXJ=AjjP1ZRo+2gS*yFe(&|EeqWLmdX@Idch~VXaqn%>A^Yxlxv{>rE$b6Gk_y9K{*}q>R9aIZ^Hk%B z7FDL^G|!;YR7!4NO;6VESIeGN5x7;O@Rlb`*BWi+m4+2BK8_7|j%1UJd;;t?sYY-DjF9T+d7YJ#QtxT8&M znr8{1-18&l!mNrPj^aIGHfm4ommSRV-5D_fCXd@lu5~Q!MtU&qrC3fWJMVXoKvYg? z2Fgw}(5dW#>0VbjkJftz+E1iCDI=+#_x}W9aw_kwzwXpuBQN7?SqF`;c}jM}v*3DH zuAyM1Ov%|c(;2u7wl&jFEh!19$Ps?iSs29@n)`#kr_+%N?~X?D5QS2_3^IDxhOYQ` zC!2kkAu$8*unhRb4ol(268t~yXR2NnF;)*wVK*5EZ)#K}6pVrPha;6g%K!<<)zj$Y zx!9(ViQ{bBofL*&+dkJ`ppaac^|XGi71-g7pU9ztJ#Or}xBXJ!4iMf6*Nh$Z$T%OvJ2F7Y1+F8MJ zRvV{icN*i$+>Lb@=k1PQocS;_NS9!R)F`3~h--Ge&qlSwG`u~F)+RFsn1z@fif~0v z2_v)#N;%#VxP_YvL)sMEv~LMv7_uDilFCo8)vQ3A5Tu<6qaQD%>io=2~;cQ~F+V6B<@0Q{S&qgEXJ|Ud*9(@rq=y#ja zN?@t}TpV_TfMF*V4?{d{5HMo5cZD4MUGwK7NeWe3B!Qv%Ir7qaGFj z^_JpUyVXWud387p%$lrPYO;a65=S znv5W;({yKHzMA8tQm0Qktx;6F(j%t{h)19fxdcfbU}jGR*RsFwruM3OPgY|b*ai8L zzsyg}oVK=zqHKs??Bn5$g)n)EpZMUo6&0?s#qB=kPpbP-vpEC3YEGmlP8-!$45V9H zngP|rR0nD^8PsPfKdb99(q2smSg5f^3Pk?P>_kK4J9+e(2AH31WjW`}n;7Jxz3t`P zX_xz?fnD1brh#IyLTM!N{2q9uUv@k?U&~YcY=8*+r{iqe9X_a2){yjGrqn6zQ?MkD9M^gnW2|**v##r1k<%9t&2^yCW6sBieXcp z!v>oIDi(~44S>by=?VvU_gW?YDUE;U+M>Ai5B~MzKl6p3KlA9zL)OJbBOcnmjA`Qp8O zxT`c{(2;p%Z=3>h7;p72e}INlN=3=lH~=*SoLGJpnw(Ij>s0HY;iWO3-JpSOU2g^*l3Kmc*^?Ze+HR&Hhz0ThjXVZWA9!LLZRG z6wE?DG!t!}z0AvHkv(-gCC2#jq9JzF+ zyu8X3U~LWtJ*69fT4&oK>HM{sr4xvX)Rd>7CN+xztDaO1g1v}1_wr@2{SP;AFZ zK7R2F;qO-RMMP;4Bj0vn3=>*`w?rnsP$;!aYlf<VN}+#3wd~t(v*cwrN6)mLI*{1Kqyx6C zVFVtW*$agy8uP^r(DR_#X~h`>mo^4zyU~BkSo#lRaQ|`h!txmF@gx)&E~LM|csL0L zLc4O(0LeUF_ayo@)eRB@YU&1{8oEK%f&}Jo<3#DZuwG*Qe(pACpA5Zs-6cjDTPTv= z_6DdBwhQHd%9`5e)kVgAEX#PwVf+1L8cqyl9%Vz>r9*)rQjOA%T+^vbunRLxIj^qF zCNltyxz|c&RtHfa`sfTB{vo%dC*VMo!L01kVztf>Y&`+Iqkjl2KeC=sKe{p*&W*l$%Fc zyfP^YD0SeNl{_m7xONOKls}5HKGGW?c0mtUJYy@RdPL$r_H&_r;Fl8t(e7jGjOb3~ z0!6ccF;oR)@HGlh4a{s+UR>GHH4|G!=tAT$LS59Q^PP%i5Q(Nl)u}s5Ul8sa-a} z7iP=@T=!w>NVn15T1Ua^$MhD=R?;^q7fW2Xw7)EDH`rg2rCZuxFi7k#OYnOZ*1Fc`YTj_9 zC3MAS6x4%7ypdXpvI8Moa}QKD)<1b>OW|0^ohuAT-bno1eTr8E>W6eu*SC6B9Hv8X2kJ`bh?^LN;MN z_S%GYd$52BqgvR7Tx;=vNAivTwX~#Y7RkF={vYuFkpJiTe<%N6#{X~T|2_QwmRpO3 z5&ti6e+B=)iG_u=L5`_j9l!?1JBHtB-p?|~>L8`j(t6^_0pKItmydQx@tM4rEmu~5 zMl1^-0Fr?~!nzrQ9-x%+(xqMG)ByHM(WeKP;H8{+au$@du`VzJ)9SOR~ew}MGfrvMYO#cppZLVsjdM81V(h&tae19=JVa-%A3aZ z1X*qw|C?e|8q?qkKEkWaO0U01W#GHVW_fU&2eh>^JKmkDd6?4(_4>H0L9iPsl^+mQ zL2aIyx3A$%deN@E4Z)JegU}ZS=nER4m+x8J-+>1cShAPJ2VS)0fAc#l4lSjr-yJ~)ZVQ*mFBk+1De%R zJn9O|JAz`A|AGM3<~WJX$~(Lc=qsc!l?S?|49_#v$r0y+g%R(>-+D@yNhR>VIr;ic zWbi-F;1tmfXgs20vG+a!IrQ<|kf&_^TgW+ho2asSnhM=yau>iD*-SFHsXRFt4Q?B} z-R0-sF7(^xQ=RGHQG#JU^ul8VsKFho7hsbaR^paw1!N<}f(<8<$7kj>m8MCmc#DR2 zW?q9+ezDZ@+I;qDxRYn*-AT5(A;t$X*)gZ#-hz>2aDw;M40^8w+D?Ty*KZTrUd@vz z&k-703^I7I;2DisOt7ST6H8i5v}QhQQ(}Hp0~yybp-;CB-s*~Uj!6AVkFSo$S5HF< z9GQX@sk;L*B;l4wnTFa1NWE-$xsC(NWs^Uq4~L?lepvW@pBrB235Ob0!2_Ey?_ ziuTp^sTdIG6hf*s5mL6E!vpSM?M;ql64$C$8`VDPVX5NPG^o(|ldy6|NN>s%)) zNS%|wa%yE@g}^eFBCueQ7FgziuuNFHo`k@XuNh=w^|_kS@glA2FTNkPE8`dWv@k0% zq}Myc)a|c(ZEF@bnb+y~(kC3zDX(l>s3=Yn@t+*rS*RdP*l6mrjUtLgr)nXlMqj81 z7;12y)S;`Des=VQiF`=U8}fm;ICfPG78VTCY0fXjECT0FN)5I;A}~zxe;;cc1U>il z^X0iFUxuM>OVUEZ*RbW03C0q^JZc+07txH{2`lT}E2hg}?~g*y!qAmK{i_lo$LivO zmPtW`1sy^&J0~u$GoF|lSk%I;t%Z?BdZK~yk0(kxq3U2yi5fv7E$^b6)Mo|23z$~y zwjx0jlT^2-cnYuQR(8fod~AM(rZJgo6_x6tKvG7lTLe1cOasXwjAR6U=#9r4Lwz_6 z^>_?*cY|jUSe;Z?e;+LCA&;e6<`H!tn;Xw0_4%4`dQa z*UZb}956DMNb%|?Uba*4v7+6i+<|F!wXHe~POMX3-A7A# zGcl{E>v`A!E+?bWDrkVVppiB-_8T1HpN`Wk0PuGiN# zwA;|vKft8~*bY4-*X>Mwf%8!GG9P+5gxoZY)lX~h|>&D8YZ zs(2vwHl-n=wOB(mBRbrmjw6ZS4vRL#>WpYOeG=sbr}I!R$msxNPdUBV%Hfdv@ zxM6UZkO)$Hz)y$Q_3mfi#~AQ|sx=uq}1Je#_5CPoCHOvjsg6Oh82coR?n zkvxqmze1IPET01nS7%1PXq`ya{zM!`JUkXjZkoH-Q0vb9xi%NC?n$gE!(0 z_9ndTV!a8M2YazIYdZxENfWx`H_V&Bdf>D-pq=vN;U49>B@3VJy$Rwa zQ?lZl#G4@L>3(hMO*qwHeorNSdP>tFZvyU$qzND9GauoM7(HTvnsr$T*25d-uj5&} zVrRQ-xANhs%n1*QR*8pcY6|zLp{XZtmJ_Ut3X3Sl8zKyv$5WA>Tp{;Nv{^CXqZxc4<& zI~nt`FDNN@J3v}{ie%w1X<9WbD{xh7pItTq=)@Kqsl()87r2U`5GBX|0dSQ)M2o3Mq-f>0}JWjRa-dFZf= z7#^q1uq;%zv><>U*8ssw8$o~}scO#EAkY%g?mV8eE}WFQ9cr;so-X=vmh*R#75ls* z*{Neqb;t(uilv}pJ67)ev`nOh%5Hn&iHoojvJ=aColVy3ptfEM?ZXJG3$MSdSHH9M zTF8`2#^M>elsofm>dYB;MjCK#q_$qw5Y}rU=TTU%{v@o|!l!XK_f@X)D^wX!I-Q`z zdU7lixsJlts|#*!y#fI*6QLE`>*mD8mD0e_g+90H3OcG0j*r1ha*^-mOo zIy+e(l9Rd8qE4^+wR@6lZZEE9uMfEf>KH^F5#2hwNgZinXm+X&#Xv#>%7!N->=9eW zBBwHg6D1?q%xiie36`M)diG5Q<|X_qMy+HQ6Mo<&p(2)q=vBk|O`~d9zrwGy7)0_c zFQo~Em-1o|t{e`N&|;1lRUNZ3ssm~Cy-QSo*<7R)JhteK`~Fl{|4FJMo@)Ly+ky))B#AJ3@xi*FZa~NTmgSj+A-}6B1Pt2F<=Hv1ptx!XnT?JxeHdwU`C|MRT*zA0Ouc zDA19XPb8x5iT_a8tlaxLv}mCX0X2R|4#>9FAm1E%ILhPXwfutV^_B5j>oN7zh&(j* zG)AWFvWe%zN112zw?ZJXH;o~epj+C5Yu(M1gqt<{ALc~Y33P&`C$fPgPbLn!D!53M zg9T+7sCm7(*$kJb6dkEX06}!bN~~_B=s3)SlXq_^o&qW}XrY$WjW z^Om;zi(@9$TBx#QP%teEvjR;UeBvLi=^s#nn8!Oqn(j=})D)hAE{Fz10i}ZE3-&up zQ}1|8`uZ|`$-Q_W^j4!VFNxaRl-s)brwJ|D1JYE*e2RR-ZLCGa%d zB-GKG6igiwN9s*{!Iq+|VcAB4eSisD1YNWcQ7lr4xy@xJ^?a!{tU>sK2NJYW&vveR z4N;4a2vI~WbCz|Mf?ByiZ}3Qw`-)nyQbNa-A~pMh8KLG$D^sjLimlW^6_7V+v9{(DWgtbK+dz&15NgNp}zWA|jUb?dFwVq@;^-65#s#Se671Gg+c z&_!Y?!L@CW9||rp5=(VKjhHNL^#~zf&r@KFQxXDqza@mtP`IZ+Gw35BhH4-0lB5Ja z+}p%`v6k)v;gy|JLLKjYAEZ)xZz1GpXIKWczR<6VQCIo`O(vCI@^lMTA#wLBg1dWB z`#c`&+Q#67M}ZKBG3-V*MN_JPEwm=#h*W9HlDaxf-&%r996f0S8j>*OaAQV}BmzCG z84&t3ptw_*;+&QL+#34lf4P!U4 zW}#wQsB^W!rCou!G!!9f2`(KPnYsMMaAo^r&o$=arG6|AVcev-=-9A}?Xw9+luD-C zSr<*FPG9W4TGLttrcQs{$)-*}F9@uqI?at6HcjHi5kxo@FyCQpV5XM_a)Y4+=% zouHpHG@6@xmga;^XVe%B35!Qnfd6K{L*7P^ypCa>(S!#F_E*7yXB^j2oo>|nmAdY!&1k)89*261S-^~hSPry7_diMW)6qdJR*Ua+g89KA zeCnlEbx$=0{!{|zDGeNA*#NE*AR3Qq?!Zv8{Q&g&HEn-~0U_jvz0*?W15eg`U^U^1 z_<(Fi2wV&(F#wem{;}3$j62b&<8jwv$Z@ck|&ZTd`U44r@F}2tub2W|`Tw-#N;meYP4CWyR8K#*W zWO&WwAmiv(`EKN=v1x6_ZWji!+sGwLSn^m0`C^lDksZW`*?qRS=Pv43IehI zsfA;nk+fJ3byO=63p*$ev?oegcpn<6CWOwx2o!8&m`u4iCS1Y$S1t>#uuOMyM;Ew15lm&;#YpHhms~`3i(A) zn2u}WeQ_1Cxl@0F6XL3h-IDR>g)e^Pv%UB1okIa5l$D133k5)P5jd77IA2G_R=$i8c*4+n;~6P=1W#je{^8xL$n^+MJzj^m zJ{AUqc*IKFI?5F2I3dDtQvQqb^K2-e3R(G~5E@vOs+~AQo6@I?`|p|bh&pHOS(dDN4ZwZYH1&3ZY&BH zqX@h1^$JF?sOvh$>4^Y0)Wnx);ygg$E3t8H{`gCN+A#`1WF-$jC~rKQa3@i<489pv zdpx3Q*)K)Zjb_}QhEQ=g{WRQpfvs7&K5q9&$dxA?RU7cE<;o+p@|d6je_5HA1z_q1 z;q9YXaSW9W=V$9167HhhK4T?C{l%LV{u$gCAtw$1TI$U!Rq#ooEQiIH0 ze19&0MQ^N|% z`w{$S^OA4_3IJ)v6tZR_>Lp}|V>qPwW!>XzGucWwKV!wc)*BEj$y*ZwCh7B=Y&P;7 z1UJ1y{YDFwU)h^etW_t~#h>6c${#5lO!CNV_0l&R<+UYL=fs#L_T_C}x7p|v8{4v% z=&4?qDW}LGiTize;+E=NtO}-+X)_NWQfqDVm+=MxHNpi71>|VsjLRA zUrEyTw@y20V_8^d*p3{`J>GI%sZW?Z)+ug*>*ETici+DyclXBP#Ooe}I;;J4JKXQIUgcw-9Hxntq+4BJ+BXn3%VA7Wh@XRPK?= zuYr%uySVsZv#3ZyK_vRYS2^ZWBUfW!46YEs8k>C5yT-bZWas^%I@#;T7^QG8#Us<8 z=%BHw$9>#1DsqD1U1TzhO%rbIgSpO37z>gbLPOYo-;JeUXb1=-s%Y%HL2(Y&SBo?Y zDZeexM$Z7`c_JYs}rXKJSQ z{EP@P{Ua=Zg>qL}vp0CjYs}sp^t}apn*@F982ilLo~4uO+L;*bw(JeKZo=NIrE-dW zUFBD1GJ89%N~hTyb!7HN!EaXfM%TW6_U54PZyk)_#WQC_>Q~EZ#d&S)|iaXr^z@LqkXlEZ@E$B12yAY zR;B-u@qu8AsC{p=UbimxLfH8R>2-f47@r*@izeh?eD@~8Urbm#VSKZh@lAMLQ^(tm z@hvq7&%-L~XOFrjc%=ZlHLVnMC!dh< z<*JGp07}1{tzDK1E{mlCuVs0uAZ5MKQi1XixyVeT$O1$%*}KAlkg7r@_S8#*fro~9{NtII5f!jbfhITB;Yo+dj(zv;r?)Wlq;IoU(#E^lIuT15e5 zX@f=}iGx7s!iB;t@ijJs=w4l742-7Psl*rw_*akS20KM0Y%6jxCAZB>N zezKCuW7GVnr%M~~t*2c!WxF%UxD{UCvZVvmCGxexI)!+{kz%V*n|Z4ZUvlz5E%??% z7Ch{1C_=nQU4-gXMA)tMh!kC*=-dCYRDc0cYXlguu&Dq8RuURJaELmPJDx>O?Fn#A z1Q6J6|3=wVj$!~}Q)>nEk(6hXD2B9$Me7RkEYah%bH$572(Ht2hDYcVg6)lm0^=zElT(y-h8p{ zH-`%CkvDv|&kvd1k#d?HBgtY8s`)(8*Wq_OCQXX^gHt-kpE8R1=fX_Y(T~(`k~ni4 z3LBZh5o110gOM(iWiqWh+{c+3Q8Nj#Q_ZMqeHIv|fI8}FrjR_1JgA-U@++(hWClOu7N=f`lM3-~O5X)Yj zC%tBd=hu`w798u8x*3E*{gho+cIGVo4*GCk|(p&R~xuec^C0f-6#A6k|S<(f&L+*)!U|(v=jb z&hZGeKi?hCC$xX5E3{Al?3q5-)$r_~LCT4(ulG#PFwtG;V)|dAlE8?q7v6f2jzmYC zr4aPV!dp*bV?O!S>1yueSLvjt_^i7oFISMv?1W^}!dp+fJi;^WPh#QCXUX7~Z&dj_ zn?Zxz*Ho$W*lfeN4h)|P%F>!Z>X1-zeiDM7Z5V6H*f3sbLd7-{k(U7wvUXiByg3BD zQ~kpCv+$PFC^Z(|9D+W(?lpo@VIg_pt+SwkI|N;JS?!tbF(389TW_<4H)L=_HBEgW zqua)GB_7t=6X_nJm2ZVKO2Eh7`+R^UZ~~wET4; zy&ff?sn^e6(!yKqpxLZtWJF$g!?F>R3ZpET)P{B&s;E~YBkp2TRWx=(#0Q&NMbd#} zofM>89dw80}ohl6?0eqyeVI`#Q@5% z{my3^r1ET{zB6jD;j*a-tX%La=LLP$Xgl&%BV=MXvpb^szZ4bM@%E=05P7PG$f+ra zgi644OjH7XWL3r$gi649c2WsA6VJ*|w^j)rH*XZ<;Y7W!LnUC(O;!oW43mU1hrHDy z?9l|_6*aT1N&t6TC*4x2B~FN|t9v+AcRW=W+)^q5TghJ^l>qa66P2L<8mk0mHk+sf za=~%PVGV%KCjcB105(?%>VSbA6TWppmB59TX(+1%4;Xa_!wpDZ9=N7$S2BczYp`aE z%d{7dJxk_+2n_2Q2n=adG8VM16kZhX+VEL`xt;q`J4?|{Gect9tOyfzzXGL?8UU4! z3WUfPyY)i!5%hp8w}se;RUz5Nq(*4y{t*zFAw{=Upb_Bbl%X&!W%9Y*yOU2EZpkybnB9^Nj>&Gx zPEN)vF`#Vac1w1uNs(!{B&%{4;g$@oX@gr*u|l)W6uoIY4JClNTJM&eQUa*Ku!&Wk z)XUAwH{6oeq1L-4@t|yQOPWXBn?`-;M2y=0ysfG2-NG`DZd!1WyDsITy$u?>P^MQYf$YL~RvYdzmrm(66 z{Ms#v)3TxarKwe9ag@()NrA^Xb#)>{<~z^V=Jr}5sV%h)yyO$G`PYp7t%d!DsTRj_*O8yuBZ=BFK%n@#Mi?-~~K zwq4u8QE5WSj!GTkk=f{16B|7nY&1J6wTB`&Leo*%YdR_k94Jy>8jeakq^5Gu45l2F zN*1ngK**?eREG2N(zH0R7FpB4v}f&?(J3HSfhO^zY?yKq7#Vg+dE^%~|5xP=Gf#X9;yn*5fK2%;xNqscWk-Rsg!SISZgR zF=xG7_(Y@1$4Q+TvhRc{oi=Bw11KRhd)kNa+L*IQHul?0#F}tRsoU(>60IUsrS1YZzO#{5qPmkY(m* zn~O*~R-3chj$9o#`Gz_Ba4letC%oNKz`(3E!C}1;-6(yT2dt0DoE1aa+MHc!kjkTp z`c~8+#(_LsY(UA5KJUF7&9JPa>@g@S93_I|FDuPKWM}091j%w|Ng?h2?B3ZKw#s3w zos9UkyJ+oZ5uigw^mXWELJ_CgC{l8lb`PYtJLON6u&mz>)HgFd@{rZ*A#B~+ay&{ZZ2a&dnx2D@)c9fbe6bI1e?8q20W=gwbG*%j;Vd1TiZjgb`izGb}dgV6Zw3a zNKNXRrZAlf6Z5#)(n!O-^*7buSQ=r2b3HT3vCQ_1zd6B?eAg%LSmWm!wMO>FX zc!XlfOt6nf4XMuw5RI*>+RI&dzq*qa6ynn1LRg}9pZZFD_oaH50;s!K#i=WskvUAa zXXJoDk*O9_K?IUVcW)}Z7=?E#Q)>u`e9+kjd#i~R7Qm$5pDoSA=vJNFy(7SX{c9^%dv5_(~=)kxnVmNFmAxW1=;!&b*CMp5NBE)Tm^xx}+NKGgz+q2uu+Ae1Y=;AEIuNRp zz@{aMzNrk?Q-PuFJ-5>EVUxkLCR?C+l-7(-yY{4434u=WfKHumkGpBP;Hh@Z*(o<_ z1TwrpAcpJ^zs_9?vu&oo`HxA^qS;(5n$3A1JX)q6f?F*TF_6PT#*`mXtscpFz@u*R zSkaf~!Y0`q?Tp?QnU z!za{M+FZQK=45XZOY3iT|C};WNbGrOFgX{oqJ#~xO+*_nA&d4ZWP$hHClx#Fi_;)E zu}_4;TAnuzv-wz?hP8sPPGS}-w_*ZqP#0;z@@_pl7_^b^FP*|lFjQY=C=f97SNGkrbj}ACo=z!6m|TPtO)DRgJ66r_Dws{*|3Udok3c$>gE3 zBSu3Fa}lbxqX-wC!33Jf`d&%6RTY6fk0$(D5q_a&$o682z2h?c0dah#E7q4h9KNi)KJwnSGG6{)m}G$dIjeqr(cG`M!O zMZgC0+lwFQBZ(=UFDLGZuaTT1YClh4-?Ree_>o-YOkHJaqw5E1ReOk%N(H(qh6H^| zIunaJiXo9P%(&n_1tesVanZ}PPGF%WQ#JHzwHBk{xyGnp@~C6n=QM6DDrzK&VHm=j zDK9k+>=^!64I)YVM-hg}o|a^t`owIZ-jpA&o5~7GfoSEY=MRoS{S9XU9s`eaY4b+o z9J~@0ulh-NNr$bt`SifnvH4qC4=QhEdbzQ_2e+&*fuIawqZMfV-~6}kH`0&1s2$EG zlO}`O-+=R1YwS8Z4do3YlPOA|TXXpknJ+-$RC$I+5Y1Xy#{xf#mQ{DkYwTxo1H>*= zlQs686~Ei{AP^3cn*ETP8&CE~yJF>cC)1KFiOI7kMe&b-)mft`tn+z{f$je1sl} zLmVdfSYoRyQ;9KjFjr6S$Z1dsIIU zO)|ksrdYq@_|4;kTZ(@rQOy2z=lwuoeTri{ACbs`7A zNGg~*q{+?a3&DjzMyD^DHPq7j>?7VuFWH;B{t!{~G*sJQ}Fi23V z%ou+7!^-E=)!JYitEMOT^s3M4p`w6TFcb=CA4APr=A+tni!fXPb5d=Itni~rrSKhz z&e=wlk_D(B?K$*91t1Y|?kpWC`n+d1Q>fzXUID(6I%x*%e4Pz|ja<1 z*94gEFCI}s*w`^2leZa9c*e%cW79E(%I@;CcpV17sd-5NWEdZ&HMdjF<`abI;-~BM zGq!blnOiYvKD{E481|!T zrj09d9OVXg+nEA12RY4i9(z)61RqAHNrDV}qR zP7N`i+d;qSN5CP{*31maI&)p|Pml}yi(hD@cSfRn0+Hx;qdt<-JH!2Ghd{-t^v(#! zSZa#&&MW{Rs>x9-Zr2Tqp*M=`V=${ZaWW+We?pVG=f?5`*K6A(uo(pk!5G8661?_3 zWFz1`UE#fFz^5u`&uk+rfhRLzYD^}qEpmt zL}HUPd0+L|{{kE844-QyOww*2i-pT<*#R-8H75nDL{c)(m1jq^7|d*{!V{{nJzb&J zrY~HRTyq!x3Ij_#+$)0p(Pa^LW+h-lN;1Q>m*9=1m&g}x*HY*NLDUT>9!XF(Vv_h3#~|rw4_(bl$Um-ELo%Cx}vzn ziL|P7t%+6plA@}C=sD?-%vfzPbDzu%8BJyNymY&&(GypQ@r2lA@y#25*j6~a)5^iO zWw}}0mDB~Pj?*+C*^lnAH3#Bt`OadM(|Hv(;pDms5BC-irY!ct1;)ij7M z4l|=Y05ICu(}4X1xhu^po-6cXbm77T?;ZvfI}Mdx4J-4qrel=}%@e|sFDkZCn4>#U zI8V<5)okc|trdpOd28mBPm3P4Edzs8rMQ7}K3aua(8XLo(<&N9Vx*`=EAM}ylm4W< zBST`LCaJgURBqJkagh{kuF`eYYm{=$c5J-Y_37j?JPkdmKQYxP%v0)n*vQ^CcD8{! zUj=obc#!9;hBg)V8Nr#(`EKP#r|Emy15t~p~S zTn=u9CdnK$s(i|$RHdgpKJm_^GrEo*c6BP4R?Wqla}f9@mMaZdxTGNPuv}9RxGdMM zEZ4c}@guNF>4aJqZ=9vu4a;@uPQxLe8(HN6QYQ=45sNO)PnTOnyHc)D8 z8n^4z*_WaZ&c0;1leVQY!rZ@x`lZzXR1|p_VdoyBbhXg3e4vs1XSP6PHBQ@~$*!#J zObAPE;;J21qqGNX(MTd0&Zg$dNN7@+!Q!L86Dd~xFuPpxv|VjGOU(u4HM22a%lhY>Bh|?1q`AAP_;IB4F`N_l`R@DI{cu<9-pOW2( z?SS>HUTiji=0KJUb-@Ofe6CGh!aFAt^d3$-L)X@K|9n$NG8`_&HM zZTS3gmk&PwNbvb%JOYl#Cw%_%>-hXJ&)*x)=a(BZ`9PY0t_PT&6?9TuUszxZBN zI%r>oAtYxn-^#B;w8jt}KI`qV7_=?{&BWJh?{oNi(`kGYU$1r1(ZKbQu~ z+jafFQK2*Hv$M8&7T<`yE`YL5Nh95Vqf8K5ZKwNF!_JALHw~a+JE(jz6gbo;SLH=N zIgud!ZET0jU|(8sLSgf|)fTpdbhc&L6zH#7iE7#u(zKr$jPqL6W)_BQnOALLK*dwJ zZZ=iAl?G#yIV&shn|`|92`K!0)r(%q!5yZ9w{~u0IsgUq{n%8pb1GeZn$@dEJ#yVZ z1_ZNeT7ji($y&$Atr6=!U&Fvc=IXs65Et|Puq;5}P@#13OHhJVKWr^oZzn+71PJ*1J=3 z8l5-FcC(Y|z#$}b;As_jdO+eYnQhyO^qZv(ghYRrAX!~+fqrxCn)`OSdL;g?SCtaz zubERWZDrZiDL2{5vTx#(yEa^M``i;izqLn>DAP?ma*n|nP3l|7Iao&2h-h!P;}oWv z+;NopW_8EWwXfeD=S?hcygLs5wO({OP`$B3+UkdF#8)jWV+RPdJlPo-q`*V?#R2n2F2pX{z=diD_ge|N6^nl=mtl1MR!=# z6|mf+E85^;U6B#5&^<{89dRSsoMEveV9}q3ML2)Y&uOttOSS3;oI9CSe?AA#t&XtV zhFY#3jr-wto?``XJa(%N};*yD5k~6msObSIgN?Bff`N$>S32G{UVaP zgQduIja78j_4|ZwyT(Lys*BRMwAR{Ejp;9dxm;WYXnc>;D{x~|e&T}mo{h*V=KwXj zd%5;(&;^%9nW4~!;R;Aq~<)UIS$crO#3xIN}xh6M{|BFd<} zv9(0m7PPfQ`-J*3*V+|oTdv?cqJo=)O5b|+N;R#`@v4mn$&V(udz>r0U1~$Ev&BJS3>B7zF)VmB)(_yz4<-0 zu&?ASDmurK6=`1y&7W;ETw>$tjnJd3Za@>A#>NtNQqesnZyxM;#SoOMmgBaYMuQ32 z7S~=9Qm{?LRCu>(^mDxlW_RK56p`Zpif|jAagTn3@%QzR4cu4Cl6bj-eQ0{Irx;B| z-?pni7oBk6JTV}qNp@)Uf<)Nb(_8TOOTD0n`*qMr(AZs|g$HN?fvR~<=ab1M+HNm( z5Jx>tVY@ogtz$A&rN(kv)CYaW`R4BQbLu>U5LJ&D)EQl4DNO`lVJ~DVt5nVY!uG2yoTjsFPm@q> zAES<$KG!C_3%?nT0FQAcvdw(|+k$ zDCeox8+IZANy5XbiPgql@#__%K_I1MQ_ZizPsR=1C;VInKh=|%dN8}muU`&+ZTW(2 zmJ#XNKqT8{iCMF1x}I6{D52FzMT1vgLsKYpbYL{@C+`22s7_j4uxRZB;79Q9sJEH* zueouQt`&rV^+PHk=X0gIqf#lV1BF^BzR$?vZjxj(wvM*65mcN4%urE%DI#Ihpf1ww zZX3)<_@wdi`AlvOD&Y2C^QH1bKvI_2ie#V;NlD%M?K8Hy5}Lw6oBKxNsY)QiDN(;< zlOOD+xo=bxA#{GGa}%t>WP*y|eWS}l#_EqHb@vxPjsi)AVrKu4DLl)aIDBw0j}Nx* zjv)qS^%Akrms;MI^0X*`XmFYNk^CZ2Q@i?NFu&iKH1V%!LPWd2aLNp7JCkZfDG>96 zj}Grr%(812L#|P&6>u&L=Z!q6noTN>`N#Pt*O9|~mw1Q z`~>u#AojKG(-80zKt)Q)TKksbQQbpkCv*h@kLe0GUC|Zp`iQQ?o*n0Eu>k3|4-TI- z3_~=C*R-o2iwRgK8t$jqmZE`8Za~L0_L#-g6K(i!*7%~v>QSC?(yRtC4zW``!N)qB zvmWU~JfN?_ByzTmIaN8-$wzo@mAGB~9JfhowPbL>DbzO&?Ue~l3 zI;vlz`W4?x^;3N1asA@z@pD~PAtgke4DdW{bnEV)<5w^LQl00h^Q=mNpW_{7{$z4n zkTVj0+CrcIXZe4g|7X6Xs8-5D;NK zoi?O0x39c{$Y?GKF>Y0lvCP@U_DQJHk}v)^)W)bvB;z9@JO%%?DndJkH;!6}z*aR- z-bZdC5MFtsH+0uIQ%7JME_*N1dnS`<)$#ERrGSFD$xqKKMZY_VyemDffCYv$vr8aGA((?cimCFft62yc&F)n}WJRA;up=sv%m>yko~{(O1cK<1jTW;9QeCw`LWjUD?lQJ~u_phDH48`L^sCrT<0El(((Dcc+Lo>0VG^QKk!)k+8qNC z7_GsbOl3mnJ4j=pL^*B)YoMh=!9_DN#6&O>Fc0dARiGX^%+!b@psGOY+TthRqs!dU z%0p!+|3BpG`Gsd~>Dum}%lq{O?s3WiKBUg_PU-z#QOiSm+2t`#hu5;50x>^$I1W^BjHd)qa&Q&7z5S`airaZ(%%#Q z82Vz)*v9+H&hQ>a9Q__hiQu(i3_qi7ovp171Lcpf(A*XWVOR@em67M8BU!^N+Xv`|BKhlPd?x;(~zTGbBp(9Ut zA4nK86_fa)bH=AmVvSQ53RP?PJU0?nEE<~yN+9952<4A=#sCVNXsDLTS0*f3P(2PS zzBAr4+bA|!sMXECh>Q@oS9qg3NlZs8h|8NTnyv92xts1#JyAqXovrW2Wg?o z`ef=E^Hcd;kB&W)lYy&4`beaO583=y5-wq5M=nhZxcUK%%&?9J1pMuZ@D9!VMaxD@ z_f(~zSIb9`Xd)lS{MuAPK642YvOD|^tl(KXm*k>mH8|$cmM95}1q86Yuo*W5en5B`;oeMZo5GSTyEX>nOhJ0ztz7i?&kN+pSg#>d(zXjzoBRS_;v2> zci*Fz{Y4cyze}(7=>C@(N^fV|fR6 zT;8XzaOvDweuyhtQ&;{)=^Fs!`h^jE^$H&DD{mI^_JmX3)zXuGL;JUa$*326u!lay z`gK=o63`Q_-C-I;g#zT~n(W8>UyMd$sZU}=lrZ`m3&&E3$K!Y^_LXkWaGSne<95Q! zJ|w;-LeaBRiD0Pl6qIr^U|{y|s0KFgUInRS70+anb@h%Ws!1aJpi|(~xZ`oZ5I?$_ zu4>Omm1}6!8SXXpq1De;dk&3f<+NAto=dD?EwcjjJy#{d zwAwmlDu9lfA7R*#Ts3hktKn(Q8j1@UoR9{=+7T3uD>oUM5Y9HmCd3wK(7tIdytBvcJVtY zCL1h*P5B)W=h-4KAtj3dey71LT1()_H1r<*UJ4#4y#KrKLr1k(0?{1us5yFM3$~b% z=|vBcxf2SV%LbX4De{jp5`n>jVj|QM&}o=uszCBi6SBEsCXwgG2ir6!D6p@5mpoFY zq3MZ{*we(I9H8lQqdEC!S!P@8!c{=s;1F8-xp>2DG7(!$LpID%yEL4Makj-&gh7ms zm*FeGQxHLPoM9$RL&|Svp!NH3P(Xo!Ces!i-QGZxLUBO@P2JW~9)qG6B_H z{%$^57RUH&60B^MW|aMJDP^I8?qdP{p$VXvG~OCcAJL7Q(B#>MeGCk1py5U^2_@w{ z5MCQKgxKP3GDoFpX)>Tu5x0yIZi2e20saxhyJTZz`3=VLcN4yf3G?wI)(EJIo`BXB zH6;CQ+{JGs?G=GJ(*2#>_xM2f)9P&3>a40e2N({g8J6Y$NvebL$gl_p>yj7hk3E(< z#6$EwN^COovl1&KCMmH2tMkC>?kE+s0Ri&K)*9@R->*)b5<<5VbY{`DJl0y6Rnsd; z>jnZ|AkI8t(~5;QQZiLg9hR-yP>u6snAn3sWR?m;xd|0m1y3c3_H>qL@ReyQM^(1W z767XM_s8JBZ;5tm?^-d$jv4ys}7c&HB&nya3Or_2eik7e*GYM zo{*-N!d+ePX5^`};6w$S`uFM3g)G^EBrwNhoNKmKlu3dx8fJ^8Y%5HIzslJMomQp5)RJ)s9&AJa8B_lj;|6v2Gu2*eYwXDnWZ zOH$luUwI%z=DXG7edYTWW;f%{Gcz@R7JM$qpEK(fk!y}6Kd5o<617oxE9$by(Q;jVB%biOPtFKFCh>=I8WsGwjJ{{UyN%*n7#@3 z-^R5urF>7hHh%X0Z=7pGGq9L!1#24u&?yw?56-h;BD?N3r$Z*egqWNei_+DNNpPg? zY0)Z`XmOp6^h}=ftg2^!hKNY|k?bV-Hf|$VDmOT-piQ|DtNV>j#ZR?vEDB*M-?wfm zeuz6Q-5u2x*8p9ft>-t;=KfCN z5IM&LPAPAqo!IhTdlQD*N*d|WR^z+-wNsDpanBG8;)Me=FOC<*dNDG>r)X9UvOqd% z(D#i-)ck@se2`Gp)Na4=hZ#2R;tz3wDx}sy72-rparIlW`raCY8ZJb0ngI#`LVHf( z6@n%-B*@FXc1pe4S0clC5i*=qOAvgVIl-e-t??|bxsb5WB<6ZLxuKp$39VZabR}0# z2cV%T5^b0Zi%AbZ$Se9uY(s4m_cvim+iI05zQqdZZq*-dnU{@do9cf}-n5ziSF2TH z;R7~*lhL1n(I4P(bl)s$F1<(WUE4koPGu%RDi&ZBqXI9*s08b9X>ZfJ27?NyO{-u5 z+7+qc^n!XaA<_7S)YB>7>y&!>l6;B$f+&a||sJRXi;k zPl;sNSMCD^i|QTeL(SGoDeoLv`3T!Z@DN>bzC$R0ePawoy&J_(cyN#t)?ElZsXDv7!wK zzN(g&R*T_DMaL;>t{DDi3wDOh}QYbntS!ckE|9fgF9vgI1T?3MLegNJC>xB*-lA!^~}*L3X`!m zK<5Lvl< znq8i35+cs&e$U~Oss6eOfC7v6^5Z%F4F9>#L~r|)V0VJ%$Mq0s-2QXTmxmW)!&LUT zG!kSVLpj~KN|$F6OwMGOtn^?ioOH4R)mArA3&AkeS^YS9Uut{@yom_LKX1+b*i5VU z>1=9^%4)|41>sT2yYUPQ^$yqTSN-AL?itKJYOTOd_cZTrBGQL3D(&diy~J+ette;{fBK znxbE$E;;n7;h{0va0HAtgV7?5?u%;vkbW}Voobmb`wx{W%*B4e^8gD{t2u*2@!AQ7s5U>bzfWM&=PX(tB<`OZOOZx}0~W|D#cp`c0`1 zOo~KVzGX0~uH8D$+^(RAb-iKQKm%IGJqgyZ_9xB3{S#Q# zO*Di_H-DH|5jna$)u%p2!*iZqDT{?0ira9S+E2kiN7KT4s&dvR`qC{EX2Xu&a zp}WtOyw_dDv=7(Ri@6_YwOXHMnG|FzuPHJetEhmYKMEad6MH1bN%f0Qzy)>>PnDrG zKB%8p>ZdBJ7WMNA{bZ!{8SEDj@s9ioFJ`Mh^#$A~0mOOkhfhwh+g<&Cx{!%W)jagmhC>F!ueZzA zr#Ki@WfnAPzhREm8vdrQdUB@RH3x(aw;)oKKZRZ{l>Fp#b~d*TDz`#;pv@G*>!1|p z?!|X^sJb3*UVdTRu6AkL%IxiXN4KXYqZw`l2YB4uApPF0yBDD;vKhb4JGjTT z(L-ZqwUi%BHTNrJtDT8;1CHW482$n{D%4B!+6GTWx(lVya)dhZmn;$(9fgbRHUrH% z3CDy;^kCQf)vr%1z_El@APPd{NK5L4uzhpnqGmp?}YMf63e^hR`M?yV59 z=^KR~t*1Kv>#Gi{BjoQ?Id?UE2U24(Pp*vIh8ZyZ7vM=U-->@yfNsvspJ1F z=O$mCDd&E*oZ`CIqjxm9Zq09#0Fad`yG-4>IxXL!lETW_Sjw{(e^PgQxZ|RDH}!t_ zl%>VyWmhj;78$X5*<%+jiyT^4HuZk(pXWZir$x1JV|fjz87%)D+!aK%dMw<%gS*jW zII8q|@%(?^-WGh~!zJj-Y)Ohvgx0z~(FL`4?n}8(Tfz|uw|Uv;E?gFIxJB6u!x7oJ zdD)AYKLqXOWlvtX&)>vz|GmNCAsG~>hLkTw8OE}*x~9H+=2%chDas(9OEtc+dy+|x)XEW2bPuabclwlk?bE!GlG#GfB{P0gH2|TC=b{NLRpA1-M!;r^)2y?rsEFa zOAOqgF5Xz)%;%@z^cD!}i^^YfW68nHe5fA0%Y9K1y2;CTxmUWonY-xe4czTfPotX$ z4nYeaoq|W*OZp~tpW+j+Jcm#TD5QSS(`%xC0h6FSwV5eT5~%@`|0Wt6)xfu$(*g=6 zV(fWRla7OAjTLWKo8R&oawqwQd_DTptNMm|A5}{u5%il3Umb=iU;t?;*Bqf{sQamT zu2pV^sHG^$@ciM=_FD5vo1TG>9?(kAw~_^2ia#-a3p?~EJbjpyt!QFA_kI*6{d7g+ zj`Sx5(NpUfUp;^ulkW(zC>QIFg9|u_Mx8?oC6&!q9n6k4QR4^`6hBV+srnL;GmHz% zONRI_ar%lH@97d}5QJjb!#KyX!GVpyY*WFg`yS4Xr&_Ev?kWr}J?Fl470*gN!;;)z zUIQ>o+X>R$yIw${N=!25vU_Cf8b+zcSH zHFdg2r+V%zZJmSr9qUK98HFLN4|#l64T5!5KiI{_5pg>zbyU^ z7f;9xcn+!kn-&pNu(fjp==R`iV8Bi7JzQ|W4Y{z{S3$AFj`2>MY9Ar0$-zA0$$>*- z9bh!VyZlph5$`gSGyGM}3pnBuH&04jKPhp2ql7qw3V}6@;GG4ki?(k$F4lL~-&D>+ z;t*30P7Pv-mr0!Q`{w++rw~nz(BH(68Pns#X1(=g<{F7y<|Qs$XHT zkn?chhYOOv%#W5b`+CBxz$CHy!eqwdtZjqE*yq^EWx-MMyiE8F!gqXM& zK@*Ky>OyP&V11nfof9LxG)SWRhu$Au2SPh1oljksc;v~kLEPG>M`pJc zQj-gUpG|VYJNC2d?HS%iHEd{8QPST?>!fXHxMUEz;~Dxzu-}%XV+(mJ&8I59YfKtS zxo5k>A8d^|5P&Qm5)Yzh%1PJK%s^^t2KbujEHkuiEhS^MMub=awI{Elumy_?s~R~1 zkvZ3v^8qqyPu-20)qpesDtc!j0#R{=wQ*>T?%79r4ZK=R+QL zhsShNhVFPh{M-Wo7-MPE$$;0-_FjHlp@b3gqcy}5|ED|49WhtOKvP>0)taIs(sX>! zLc2ULYB*&}PhRt{rt2f#lBlQ5*zXpHc798zH30v&{;%7TPlf3{v~#X3@_+LliVU1;cyDR<2{u9z2ZH0abZ{HT>}JF14p8;_DfPy`z5_A0xeOXWy8)i z)JgUcTsjTlkQpk*S7%~v3de?TpqXein;$6}^ zPA``ao!!8)xoRL^8|`VouriMdf(@h}>BHX!8Wl}TFWpy;Vqn)$U||Pzh5;xytV1KT z2^q9UU)849zUPG77);SVpa*`~&u41_MixzW2(s2EcYt2i%tBiz>;s^^OU0X;sc1Lh zZ(L#*E2P!eG*Iqx3V_cY5Rp_s*8CpJ8mqbw2^#_)uHQTeHli380r zn?s&)R8%_u`@kXYfxWqfki0xo=>LVU8~ z>-xSUpW<_K3}z;3+8Gsq61i0BipVb?MNXWT$ze(HUV!K*+#U|(2^2wgZX-OC(~2Cb zDOBkQ8$I*O3ZW9h*+(oIXYi~K&VdjNNToAM5R+D;#CsvnMCJ@HzG$As4MNd|09#5J zLR9vgDvblpj&{Jsg)E1nuyAU-@wnJgLn!-u=Z# zg%{Tq|AX%TM^RKj_4)}^zddH@dSGhKw{9X>DUM9buO6kRIVgr&DP4}gi9XVZ*VBg| z7aDSsq3IYO%RF|PPgg7LS_HPB7p}S%g9aKRJc&z7+omM7r_n6JGL=9*%hdEa<_aqB zC+5a2u?|!lu?}RbSV!(cSc)u?F;SUyl&nTc#UV99Ij!PAw6y}02#(n)GKC^RTA9SH z3}r1wZl5i+81;oxD?Z9zCWpinvYaQQwnT+PHN(7WXc6{U8lu7;X%PbUlommJ$V6*6 zhnSWbtbMAR*%Xq;IB_0pl?N28F^t$Q`gU!3MQAqybYg($we(Qnrt!Aa)_2>~kWxx< zxg|dwmpi$v{+!g@JGkTWK7SayM`dt~rT-DMJ}$M}2ZtFOw}$N6Z_AqCV-j#cX`J_Su8^Za7npg{(gY-MK3geF^l>uI{P|j($%zByWH6+cI;>= zf7*4_`EPz3$JUOB2K(_Zt>T`N`)Gy%B#2@qcL54bGAVR!a{&l)o4u8&J1a%*YT8GBKN9pOPH}Ce5G8 zG|+pw?UaTRuu8d9U-a#ZQF^6dtL0j?V3nX1BNQ!IrApBN0n2OUjohL|t9`$}wf26_ zbIwfC^dInfGnsk*?EUP$_S$Q&wf5R;uMGjG<@@3j>STph4j*htRjreP?KS^R<(?Fw z)OuLF&r(0CR6k#L@GY^hJaw;9SMV*pr2(3jAJ?0cRGP+3AUnLft?nX)93EDVF?ziY zjdl8GHe@GV*Vat$0a(WbO4S7U^F92*ER$TokoQ-aUgh?x%(rRgG*L{LJ0Ql?!4K9x z&EpzekTu<76H8_afST>slaLZC}vE(LBWtTV15pkxrDhtVjG)jgF65;WS5hL>Fz%d2Ga7#r|GM85M_ z!S@|(rN97G2F}a4T{ZJ$`Wkv4-W&j~l2$8;x-f$?^>B_JTUBLRQ)SAkOy){jujG^} zQ(k2#pkDpPY5rnOZjVps*3EPi0Uq;*xMu_{w*w4@i1>9wFx(*p(bU#3TJ zBS$+ZV~>!jU7WDBzoJ+@^Sw6~t7gu*ac{9^=B4~Sg_sU|i&JO%{9QYR^7O_ zzq)wAOqc7bq38~)>(L!3XAsmVDA^a_pm(mb`K_Irh=XmVEMPa_pm3mb_{-Irh^y?@g3RQvkW(PZzRv|MY+Ye$p4 ze^^nqb#xEqMqHcNOHPZ?L$aK*$Z!xQUREP*rU!1on=wP7X5dOnghRI;2U$1w?E>`WJ8 z8yqVp<;~5dyyY)PWbt0TkSsQKz_KSx>0$_DOBe#+xCE{xMG4%H1U6gtRE)AY_&!Qt zW(HLzm%z1>q6BV~NZ?SCOW<0jD1kYDtjgpPxRxnO;0AIrmgEw+mMKc$2DpovTmsiJ zMG4%H1ZEPkOgEcZ-59&#f@-QH3HgvRynu!zb}P!gEp|F-S$SA= ztOe|-pFJ1}JHB`8(O6Mv1KZN#9aq7p%%awK1c ze>fz5vPgWq`~lg*i1j5L*%+c)yfn(ie<8B#u<|R@&?Kt!iZYYQAEyxZJZMrm#;FmV zwV1xx{LtrAgcHx7dZBPlkrZl)j82WlqnCSHh59Ex8-`;<{Y?*zytp;KCjTtF0CWvelxHwP2!BFi_vTh{MraG&SF`Y9z1`wMt12=h3r%#f# z1?wu=J909d&e=^ZcaUw+AUi4K939R88Ifo-F> z3z+AWcgz&~ejt%3IbI$92g$82l!QjTldQRDYK7A?ZD7?dzj*58NSt?9d?6P#WK%0+ z%42bgS7!X|eGnqPT^u8qY_dX5j9G6{q9jn6^K)A*D-nh*Yd2=SyUGft%KK_r+16%R zr(@O!tE>=udAOF9oj8_tGG=|O%1VEhd)1}@E2L~$Ct}uHVuQ;TKexrKG5Nm8SL2Jr z@den-%11T0KcJR|iSR?rhrQ`RrMROSfXaWjzE*yXr1C*M8JkW@_S^}<0<&a2tvno` zmXlF~c{{64=GD^ZxzX;}EV@`JqX=%f8HOVSn`{S_JwO&6EuyrGu8@SDkpgkP3**O3 zySEw+JjHLuul&^-{I-hj^mscP&l_2DtcArQAmRS1&BKMWGBu6y**!(4<&a=}Yg%py z;qKhvVLe^$`zv>toR+1w&4(Z7dOFv`mavh#n?9o~ui%c$`eK?J_oCFDyP8Zx@a3a? z(S1Ldo$1n!6vou-%&hTS9(DZEOfh)ml@3vuSwH-W*DcI4GaHw_CTWThRh(3;diDI2 z={hH!H*;OFdS9{XhMDBGEQ-JmCWXaGeX%$yQ*5h*p0@u@+!&62OGl&sBj2h6Vmqedp2SZr|yxd&b{G_yzY&ch~f-QMA)HqoFa;3otWoz(kC~_I62Lfd_QW~a@RWsd? zO>7IqM#362yUl(flkkjY6z4KUljGzc+)*GTyj|S;&fHfRY|}WPoUU;a3%d2MBmTx2 zhd1fT7z8H0qRg}yJ^=xJUxuPmOnhHZP(bT6!t>U8clBupU?BXZZV)!!7)U^m{$ zpSE0Y`O16#R)e4*p8=AVf5cV&O;`^mz;dnzB_aZXdh{<^t3r%C-btf7WGW8&!^;+efzvg!3wws!vB(#itJ3H5&^a3TUSuE`BYQTwkR!LVXGrJs>fnvMiR{_37##-oEK+p#tQMAg={;l5bO4JL4B~ms z&1@ekej;dG>29x7qj(_UigA!*p0C_AaJMoWz8z-;H~3L)0oC^1R5pA>UEayALudhw z39qqCn%Y|C<;-td<*B%|P<4w5&m=P!>58Xr#cDtkhpL zOqsE*={fV1i8IlUGXn1R^O*~XoF83iEI){-jQzT3|pXo1`f-#fAWg4~^z*JkAiGi1U#Q>&Vn2G!BN9>fV z%vp9AV%D#aCxkSqZD1{mxvU%(9#C9a^2)a+ub`BMU6C#JXa4hH=~= zmdwV&3`HDQ6O|`onNf{?F%bLnX3#Bq(*aS zwt$vAwr756HW>DF*;pWNV`(xIhhl>08Iu=JY3UZ_ftEi!3ibUF>I~^J`oqZ9{4CL_ zHME(6xWEu6ktJ#uEf{W>WC$%MC+e7T0@*^jajER+sYKZ`$z0z0a8!A%65+R2$;4i(&2Z($hCNnot}fpZdR5ZXS5I;EXs^Z_p+=u-Q~c*!NaL~XXX6(aFl zr1)swp~*{;ZdLdZdGIj>Z+7oy8iw0BqXjR%$$n-N3}W-!wRr6mlSo#IrO)Hj=Ua_< zN+_T}t;Egnz^@)i$_?cc@28UArV{tymOiv!daVZ3WB-#hGhggg=I<%*;$oRmyC`i9 z7s_7gPhBo-O=_3_pv(jck@EJ0?jKbh3ecmS+`i)wNZdEwbyy(ld;~X#!KTh(!nZv! zqI|hRG@8Jd@x5Yc$ln0|g5K_aYh2wY?N{8Dt^97aI;*xaX!oYilCttenh9m)6L+{u znn`(GFU3O>BJ=PH6C%0#%aV|in^O$_B<#B|T`W%Ay;IjY^ z>~PM4?A_S_Je21Mo_uqob;U4a%6(SeHBzTgrTwtNwGg2@p~QB)MwFPpiFK<@BbP1s zmeGRGIG%zT6(exkG=r}Dwb*sOKU{lxtrKfKCCkfGwf9g}j+4M~wO2rC%26bp6-L+) zq#Qzt3-iG|ZEE9bzR+VL5q}EVT?CHiaL9r&+e0ARJ@fj+EU$1-5GzXsR^oosyk)aE zi^K9@R$2ndtjt(t@QIC`8EO+7_zvGQL461Qg6v!NleL#p0#5)PT zD~;yREUQ;v<}gPIc<#zZ{FZO*8MdyBjATvMkjB8VKtQM`S_a6%JQKf{Cz=)c>`Cho z9T?dI?>!(Nqr<-elQFAuc=5>l;)_H3$jkc~-TP-`1f?X$y|NL>ofC4p{4 zkj<5*e~GtNWMBkh>w|!zEe`Dk{)m(ysd=HwvSU9M`r4EVamn|bg-fdgS5whR7WO@2 zDvVSD3vjw14jRPWst8PL6e^8z!yKKa$0Ar%H&V-pgfy*}ZM78I()y*r2PMT~fI)@G zolRZl6e2vSn<9zb`dgs`$rtU^W3p3&y@YprNtftgMH!kDcN}xX677}E_4-<7=2+Yv zvAC@WzKTa!h@uoDG<<@7F*}9PpJ-8jlDPaac$_e0Z?mo=hv+kPpFLb7y#>&ww?Ln$ zDZiOk)Sk*%QY6BWx|gCU1oRY=VZ4o}ia187C^lK!@4d;yM*Xli8UMY|k<9AR^yRl5`n!K-0;SwDZn}6W=DRU*7ac^}52m7Bi$nY$>Q_pEP;TP-AH2ra! zUZo$Y9;DsmUJC-&43RJq_=oXN*?R<8ob*$kuD-ar!*%* z8^l$&rsbJh*rI3MjL+pDNe=#CFSSLD&@Id_;BD|;md{^}# zp}+D&O*fhrQR-V*5ys7iQz z_Qdq5JZ*&eBiscv`|5~vBinY|%beRp5;>amDF1puPsDhr=!rSc%wN~&363R-YNBIH zTB=v1Z9gNDs`o3z{hajc&A;<}^lK#)NBh;VHq@^S_Bgk!FAW_hZ+I}PB3RI!u^%va zfOlpIqH?=nD{?k4=qWm1gs-Jc8@9|s#3w=qItkva6IV6auo$u|6_dfqqyAS#Gp@$^ zjp>dV9>x;>>A)0bKh6;JA%-Z%KP8F(n`5V}FY$%Ev1AfhUV(bRdWrSdWmTYuNHv|2 z;>7DDgu=FQDa5`@-xNjZ2=E5+08?mmSRsYF3NRRJUu0#k+Gz$}y|ocFEeIJuePPBf z*vCe3OYzI#wx}&#dy)DQ^_R`7-B!QN`adx#r(0=)`6iM5##$kcio6ty6^7d6IS&Uc z<8bi%@#RJW{a9zu>REb2{Y>1UXNcxUYG{TRN}~WWP>Q|I@5N3ry=vd4=FI--MwA6UeF=^O;Zw#M49!&syGXYZKl8C%|103oR>%8eOIaek zP$T;3u*CatfDr2f#{0RYOLXg9yNNqjA79BGNz!Uxfo@dm+U39Z&OO@qw^!dEi96#gM(<=jxAAtdNoJ$G zhozXbSXr#60%)+pt=u6^+7kP7iW%`nVz>P|XuL^ZA(m`B;k5sfcJF z|7N+K%q`vrv#s^nUR)w|U6dujOF&a(;qkjw=k0(rtsV5F+^!~Qinby70IiC6#;_G4 zGmM=#b>?zydvOKPaJ$Z&T#wJ$vMr+B7iey1Es`x*xS1wY(Eu+OOr0SXA)PZO|3)oY zQ9>H!Ue|bOVY%qHG?FtOatv)2J|#Bp1T{$YDS(P~3XM_-8>Uinzwgj(ZI*7&lA(~L zLp`21^-`n%$(OQ2f{`(~0hFomKITWAjWmMZ$(IPF#9@h*_MA2fkp}a93RU6CW)uQl z@OFCeb_iF0lL}x_iK8Gi6%@p#<}A$_JY*nm2)yLc@nulUq*ZP=p&n>P>>GAo+KJc)3S&R^`o&I4li$VC`gv39m!re)0Wznf|5YcHsr8d*4AWtM zygQUbq-2!1B9t(`3?h#dViZSyd zve~HStT}E8DMar7!w`?_n|kmk`cq*HzDC5L^jBLkFFcje$Doua{=wWr%bbu`JPs)V z5o0QUiAH}5YSwi^FL4DO_c4xH`r2KTsu(|>2F=MO7DP@tTsY@(>rCK62%qW|;sy(y zlzFeB&&qA7I5Vo|eD>IhXIa^vh1C;v+hkv;*)&&`SN4pIHzb=V5$Mv=N`mNB0MTIL zR{@rX-~&?%^8{KR$<^@n+2I@)Yp#cKOi)}O&b`p}*+VuqjPMC2CXNMsP5elcMyl1n zvWm*UuJ|%tV1a;5wL)SwgrV^x?yT4>WmZ;~jzZzq~#GRbIfY5@`0z&SSLIK+55z54wqfwm1 z;Y2WRotT41un)R%9U@2PM4=Y>Fal{r2u%QfP&Ay4PM$aQazFL{<#NW?I1-2PN)@dD zL2cDNl%Eav<!5>6&G*6hAlJf*3{ORT|nai;{4ok4P6q@D55e zM%6No(VkofzldFBESY|KnfKGn>PZrvByIGhjX-Nd*2E)27WQvL_C(F;V?&m9#t9Mi zNpXT^50PZOTb6W%s{-B?4AY2;WxIm;EJGZA2OtmTJ)`Oe@}524pX;o`hC*XS7Wnr(0e< zE)o|xR2E{MmoLK?o{m*UwfJP(t^j+QnxHUI?q?{}#n~?h#dd#gqJZO~#FH#&+9^&a z#HF!sT%g?wQ>K`kHKI6_3mqxY+q+O%EA9qfZ&rcwF5=Q7@N!JEYtZLi=VUvbNw#*7 zY<8lgNwy}@{$SXw1jXQKmS&QzsW^YROSXML6XAHfsm>dcecm7#s&m=4OC-rQRfKG7 zDoB@=>{;gF+Gx)@n-i_5R^;^vB={+fTC_%?u14`@WuRuq4+B7AMfpIyQJ{?#8zVLG z2Evr$;w|_+aQJ4~(3Xr0`+E8JpZW0n#xCehN^+${2S;g=M%=Ea1(Bo)n~Nl(phl4t zP8yYNfG-6UFsbeZC-aCMb#!K;M`Hk?rpbo{4zLeckYI7}<4`v#jdY&S)}ES}y8dH` z+D5l7Wi$|iNU6T!RVAjlXM8|t!%~IMj-h}{GQ7kkgK47EamE+;Rvn)k)8je=`EtcBbf%4=9}uj zWf=NNu31yjdPmZF1=q2f&+r%M$v{TwanO8IgN(8tSK0D8uwh|-dNz7AG{~aQm>$^4 z>Y)K<%dts>FOXuEQ4w7L%{t zsT_Ml zqeB4!J_(C#Aev1o(Nj@0+bE!?#_FPZOlBR0LTi^Ti9}$KmvBbqoMlyNQD4Y-aG6xndsXiY~5YE1!)W>LqL`x#HSvLUHk6O7C1 z_%^gmMH#AEageRW96DZ6-`fNA?Q`nm%;Xr=BM{35!bP@|BsF>WvN;>c<9H%6xLP70 zQOr!zTOIFd^rDr2D5Zprb9WN&=LXG;Q4GBf8@|_P5ctLm$@2Z2Uos|FM;{tT*iEr| zCYhP&eu*)9X8t&(zm^qtZjYpWe2-(9ZzinSnoE?T)7-O?&vQKSK{|9p0##Ft_dN4a#zo6{;xQ)St_(i}5Rn7^ z70h0xX`U3#os*|W=A_}=q>-$TLN~^pR=*$9mFTFAU=%tOwI zfHrJMSY`GG0Q`SSuBRzlzKe>c7VuMDw4~ zWQ)V!t0F&yuc&x0Yc1BOZ{cL?3kToz?$%KzTQTiBX0r8eNuY1hWa~vfZFo^+`+1%1 zf9FlM0&1S#WQ)kt6_5L6#;Mcb{y>8RHE+avHc?HsPIDv?3MovsUg$4gD6HLHqwo)e zL36vxhF8Iw;4I(9$(C{C_k{LGCG-~puX>LUZPrswK5C_7MdVeSzQC>XDx$?pUMYY) z>cGuuwbt==n3yki?DL}XXSv#eb{}=nC956SZo&$~B7j6w-}S~vkV|**)aO3@<>WQXFMBkS>{#m_DyX%zpuqf&viLz`jYdqJ{SI3ExK*68J!F=W zRQ;AOe)QdP&KlA2EqIeWwo1eK92E!O5*hd#e0Uy}fAi&%)sGi=N1;0olEl+l{aEKoteL>% zm^Ma}=y%HMhiunJU;WS#5|JmeSS%%Lr^_H&aT;=~vSt02&(e$bysSeT5>C*G+NO)e z^}|>_f6CYPSJ-~mwQE^?#bgmbDR`Zv*$ZDt9YUyY#1S%8>(CpW4q0S9-kvu_l*Eoq z+FXb7oU-JrHMOshW%kvo;74$RnWQSaMd18e#?GXzyFGKl3{N&G2~z@1O3c^HmIs*! zloE%X^PmCQH2ul!nkSyea4z!m=I6Cu>t0i}IfFZp9Bay;H4Yh#qG{zj5kw4oZg4WG zW_DoK?xO$8cpPl)QL;$gKXewZM z+vTtkq1g}JtLm>H+_(UJ4C7rSKPYy^bPEEUm|%f@gqX~tHAG%*kyju=+qymmIcBsV z5EhM3n7Za`xZpm!lFOtVFKx%wBo|f{+FYP1oCk{)BCV6LFcme0x||R#9;hkhbO9>M&l}gRL2+<@LXeJlrS$Ae&vX zPWb>|*+%>B*|}^5LUvzfL^-3xvp1u~=Px*VOdW7AxM{Go$|v7PA-&ZZ6F1p{%9R!X zSPR1E$rV#h9X47TLfsJo39ygq3c4OqmHU9&TEkVXnc1gpPA8n5Kcv*70VzSg6v(vu zNdcJ@tF&n`DLBtW{lw`D>L*MfTDzxr0Hj2dZtvE1R`tf5%HppeE;lAY&h;R5fme3 z8f)W>ysAuhLWgNMPpLSDzO?h`|4Z$hOJsz24IHvZAN%gH(T%cDkVGCAi9DmMq{GHw zi+>UW5fqgJwryFgwqM(^@d3uTftoS-USU8Cj|(G?!CLd85wnXNGH%|^s?FQWe_i>{ z0AlWt%KbZl&K5P}p5pkKZ8Pe8xamAS9N!##R>Z?ce~!-64R;oxvfTRz2RMDBe9HkY z?9vu@x`kKW`#G^4%-3>$L4Fk7p`4HLN;$=UYdJrwoD=1jRHiltQs!;H;yJ}tYdJrm zoKwr@6t5(wM-0%N#vvg!%U{$tE6NY(61w1S-QTA_p$U4?{ZuAzh|5PA&;m?2wGYlO%P96wvhYv z^Gt|q+b-(Wq`4f8GP z6TLStuiIUow#PzzS^x)1Hb!J}MBGN|PwKhg6*dbrmL_~rnqi~+-+TvaYFk=0N3-D% z*v7A{8ysL7a6KyLn`CxKq_%PyH~>K|bd1w;jTWT{MOp|O&E$hPI*_-4{w`vj?R3AJ=lX7p; zIAGh+WF5QH(T1IW&W~52Jt{L?SyynUrdM=NIPs*Frs)3q{bKIx%l_m_k?hZf$5V7p zYF2*plb*UxN2F%u--O4tlPBo$qv7#11@F$vUkH!i?T2*!<0t&v^;)CO%8!J{v;9!u zcZbI_jN_J{`xDRn3O}v$ebu9Bq~AE`sV|kQOICh9JgzZTSN>^uTw#mD z<@>|qT21(}@}}z1^p@ZIV=wv7{2c1?`tW?N6XU^;d-C@iLC4`FEnlOSUhVXxWerI{ zC`a%95VW2Sop5;xj|Z$IDP1l^xmnM!FUTQkmV9McKq`a)<7%?MD`L>5UmqYzXSH6~ z_a@q__h&*N8v9K8**0b43Mkr&VDza2iePl_pTX!9!RS)LWEAYEEhKOIj4Om~KT|Xt z?vh@fZz@mJsMNA=InM5|a`i=JS`gRo-HVHjU07VSlSN={?MFZ?T2gtkHn4X7AWNG| zq_bBBe^6zOsxnTw&Nk70KN5i>yyiH_4y!uC2ic1js;S~6r$d5!Z({l zI<{@1#FqxawxPuPgKF6$DnpXaAqBH+k|rjVdKsSs7N(i3W8qLYVhwHfu!kCqLfwSO z?_&eh4WTWsh>pNhMs$8sM^i-iAC80Qh6yrShP4#5UZbq*S3vrSnVDbez0jy7}A`nfjmWz z$77ZEG65=Zb*VK&UhWQAJ8^IkAJqnzBEeg*qg0!Q+krOa|0Jm=>52;!`|>Yhbmf>m z=rJNC^L|bNC6SJ6a21q3qQi98$=}3SS;M#1Yq(i47Nu2R4UE?GmkNYw@gCnIzy`14 z$h7R0nDdbFvaXpqQ?=5B+}ULA0V++L!yfcftEXI6S}BPIQIdZ&=A!mylxEWM#HdCryFr$(ao5+M?)p)C{h$cE3UhT5kql}isE@~^zLM+ z;#$MSwX8UcgwaxQ;wrJYHG7<HGplThE!Y##Vr9kSctn-Z5NuoPC zaE%3AHvz_+&jQ)=$>I@W2rk}b8~@12nFcgw@ve`e_%Ggk?{ybyBQL>vtS@LA9i#Hd zRxaMd0Y(H~h#OVx<&(dou?sgKrgIO3v0(%PV6TV1c=9(mN-8T?z!RuLM>Oa)sf+AO z^(+$$^ChYl!50M-Ff8837&b`s4NvFKE075fgy~;Q=g&z_vZpZ%c5g3qni=t`1}|`L zz@|<) zi(Oso;8oBZ3N-^t4cHS(Z3Z3s!oela0sEq~h=mjh+-2G!JOz_42md0g3%PI<;F+S4 zrtR0{ari~YEN(TK9+ZoJdLSu#<)a!YQjdW`3Za@Pp};sqBubtjVu-VWBs6~R++X9f z=t$fFOV2KiP9I4d1)ic-=P36t!wsakaYl|$>EOiu33hrKgY~KD)}0SSaM2A?x&3&zEKf$?$@k9=SYCh%%ASm zlhPg@O0y?R!wN--2oQ@`liNhaw8gk$lFP1-fR(sC0D3jY;qK!$k>ZXQYq$_C?;xob z3FRuZ#B9@$!iMsl=mlaJ!5nq)F-=KY zD3vR2=RevMXs9;SLsL_sa!q^~oE`sw{<~1${AUBE%|e`Dk_4k7NiZIb2PfWSuU`79 zv|UQWsb1gz$`sQgl)A2kVfDJvTdJ~}Rax)~u{6|Pi?(9LG`E(0Nry32G6|;4Vgqa_ zayfg`i|i#RE}-^DMMC0l5N1XhqAfJ(6i(4YV<=BkLSA0_D)KeUv4x_g5WE?IUqjA} zoN&l7mNk`sr_@Xx=>ikAjJaiOmM1ED?vaG(xf_za`o{A#wzAFI_0hU&0oV#WJiV4M zO)U=XTIQd;zloD>`yAlQFc%aZxjhR}ruu=KMujRV;leUzvWLw_Im{O#;*RGNO)z9O zcs^>dKC=qY8J>>{zUZFWYJ$k-c|g)*gBl#$$Ai|rUg!yP=Pq`80s$ng1LIgZMq{`m%6Op zMJwzHy~&g&&JY36n(8ubFKT+$RB2P>dJ$C~(|(o|F;(UrSgQ*IroB>Vz&ma^Xk(zQ zEhU7j*c<`?9iVCI3^}%TTt=Y(yY=CySgxd#P*X`K_+}6*woviRW!&dQU!6r+;|=5> zCi|MK)0ikI(Wksc8ippHJbrsH3`SuoP0&9auzDu&pg>c_swsJBio{@$vM<97S}tM) z?P3kE5GD2?rN_T(7m${#Rg2nX(s?}18dc1~#_6Jl)zV&!F1lN16mcK_7cR0uWiu0R zdB0KU+VUj#!_&K;Y-~bDK_*MvLrs+K+un-WHZ!rIBh1;0>VedgWT4&4O>XSuoQLM2P)mRTv0hCM}TL1{V1nrcN?${y49TCfVj zsY6zMO%`A=%`-6>jftdfGGTAgD&7A|Px{PO)~1q~gTHm?&pvVE=l=Zd*L7C$fr`-| z-GL{qC%(YYrbRCsUx)uzDt@&l@w&hbFxD~k5a1xl4u#N2W>L)j7i>Ewb0>WXCIx6x z4i~ke!?a7;HINU4xXzdyw1`>R$qg>zfaZh&O*^h?CvNcA?Y z=Z>T`WvbS?cbJw`a-HXaeG~|KNwx`oVk<{0iw5Mx0I{{Ca^E4JPgxmSRT?g|UZem5 zo2PTRx%!G?^pybM^2b~mW-IervXMTisP| zP-Up=V5mzC6pBNw6%K6vfpp{8N=p_pp$Re$+{DV;tA;F7s+OZvu0U3IkJccB*s9uO zGV|fL{rTJ9{Yzi|x|r9@2R{Gre{tX|fBWhCSuF1m^>W4(l#>n2S({i#+{=>K9Xn6SZw7WOZCYCCM$fWzvDMm;{u_yE} z%y4oDSzuEu{RUY5ritmnZ#gJOR@BACH^W+`g>0QG-?*zpn9F}+?4q?C*i|I2k{yHX z^`fcxVUzb4t+nzvj3&G#P}LlOD1;!b=)ODaC7Eang@Qq9i!2FV+M3a8#!IPlyOgVf z4A$0tn;K4%kT_Q~E?TQ7nnZ}rG<=ipJ1n*%(yaT_WT2LCdECks+8OL5J2NH&9R+Jc zpUNQQl;ZobI@;@p4g-c)TAsx8* zroj)0`i3ltu?IK~B_cld&TtQ8)&tD2(0{5P0N5g<2SERrqu#oc%{y=Zn3{ zw!{V{W6cv49j&vgwHBkua?xR-hd3c{Pe0iMa&zlwT(CXuRcyuq^%3kofQw$=n!RBd z0Cl`t1A=eK`iUu|Mhygbg)~K;7xpvupV8}JhCn8iqMWw2CxW08nS*q{39TBw3#{0@ zAmwMUzR|fqn?;}mh2-d)c9oCc2nu?w@@5AYn|Ev!GK(zvo`rtGK6$pV!Q^Z~4Fbio zE^Oj?gw(??X7OzSky2Xd9Y9XJ=)T#4cpMynzzDEP7#i0W`5Si`h03axFLZALRLBfd zV29NSgW$AX{bZrLmvK=f3%i6lVR@+5=%6EjtwCNZk6tTM(^g2;wAeoC&O+U&`@)ef zH)kv`sCYVqXdiWyiLoz>F`3aLA=Ge2enVMoE&Vnx0oRhp31nl1$)ZIF1Vx*wF?;3B4Ci9 z=#rQge0iEMS~3GO1VQ4MdOQvq2tdIAmyDX8v{ps?$>|zMT;oM!@nUNAVRIqjQHV{Z z(Nl1vGO97dqLBDT7^nT@Rpb#zxtMLl6lMboGXMh$LX1Po?5<8OI#lClDHzTJx1;m& z?!SbALg#$y$jQy@l5- z6nadGj{2Nvz#;_}D=LPPMcfIu{Z#OXzHL4ckq@b<8|kvdz0mRG+4NA^e5~dAQ7m1Sl+4%^+#}1ib}djEpbeiw|ElZ zK62y7l3tQ;03V5s*Lx)RZcBn*fmraHMXz z0L5Ba6N}&T^|*a4;hE6K~fFGJ}nVwpAv&p~}=!op`Y}5E}WiipLC3!?=lE zCf$mHqTbgMhqx+2-b-snWh0VZ4+g}@yjh$G*~0v1D=JZ=+^_CuIZw1;Q2q?tgKqqo zrj5NW$Mj;zIO30TbeS%?T*}9IqYY{ti>12>-RUC>!f*Kt`FrLdl*ul2+BqMMzEnpY zQ*8L0Iv?MUaq46xj3ZaU@6B2FoyzNsL~mduwla8BMiK?{Q!o-XwTXhbaOA24i7pz` zMxl_7=@S;Ng$|UiKOyXRUw|z7g2}&RPw1H*Z51Bpbb_z3NFoi zbcGXWP=W|kn1wGNo$6QOT%S}#c8dgs>m7Pg+BRgQLE7tV$ie@4dfbPst;@^1{Oh!6Je+t z4}EoMFL%Oah;mk^C`H+2CgBfI4v{T0cSm+q-oP`NjD*zUWyx0U5o-rRan@KxM7snw z1$e{gn$WOePDv4_Z5T?72M2jrM~N70zz6HbVs}RH>LkJ^(Rip=3b;54FQDF-of%|f zpfin1Ln+PDE}w#kflWlrWs>5p_vt6S3_!tyZ`W{s@-*S#*n@QM+sG&#QCV-&gLGFt z=vt-RqKADUMb|3Zt$MgQr07~@yG;-82`Rc(+3wK8{*a<;mF;dl+#XVNt+L&#hr2?G zu2r`C^l(o|(Y4BUpq_HS9`r_yJ6L~sP!D>eln3e$59>j1l=4vh;jkX`Mk$Bt50C0W zZfz>) zqHC4yHa)y2r07~@yF(BALyE3dw!8Ikdq~l>%66|F?g}ZoR@v^;!#yEI*DBlndN>eL zbgi;IsE30gMb|3Z!+Llir07~@JFJI?LW-_cwnz1FD5U6GWqV8ykAxImt87o`;Ydi) zwaWH*J>}?f*7;kId$+T&(dqVu*73ajxq+T?5n2v*nOzl4j&8 z^3Fpgy*{?8p8Zq0mF5ypoAYD$37!B zomK^-zrHh*r3KpzwIZ@m$l?TJR4!@)?{cvzxyXz~3=)~Qyj;}OBgn<9yD#I5SRs{U zo1)YxEQWDbgVzOw4Z$G+fzoHnlMwQ=K<)kS<5t`_%sQkT#(Y5p)v+;9{H>l+--Cfn z8Ub@Qa0pT(3bLRY$Qr3GZb&lvWYb*EBMOia%c%x66gbdeaL_LXiFE}BMbrP*0Fg1-w z2BHjiaYm1x2E6Nx9-ZE`puwxIInh}Q*lDA(i2bM5tL@D7DT)W-5O6%X^S;c+C2PC_ z!OVf`y$fh_km5M&ypkdGFjNDf(){#K>aFF zZu_FBJ{_r^4Ky@FJYa{kHDD0~hJdbyYw_mE)9jDUnTvMk=UYa@7_|FTso|T6Po_d* zw&|#RlG%lJf&lXpJ}G#H`6RtW*`f>Qllu7i(jBFRGGUZP6BnbWNP%6`{C+0+AIhj%PM~?R0BmLXU>#|xi0AxkhFot4gll)}iGsUlRIca4>vkzFPgk)DJfQPQnGl zVp&+v4=x`HWG{6Cby{v4??~MlOZO24YA6!VTYlS6X`PcG?{ehbzRcI%StG_>r#uWP z+8=7cx+veAM7&il(ywIL-k~w0Kcth|XPpE`moj5rPpa-Y$r>)yzLE=!sf#Rn*nrS^ z9S@j)NV|NHN>qO4W$KYmr!=uLOD!MvEGYJfPqn#wLaG{?I!7XB`<f>m*ks(8&%>-w(x8$&!$QoUmG~SuEh+7vxbOfPFe~t8+$0Z zQLdn)jnP9*NqN0(ol&vnfv>_1KVW>Ke1Q8>ixZT+NRLy{T=(~R)RPVZeF{iE3xMAm zP&$vK0q=Nw0Ts*oiO{35Wfv^iHsUoLzxi)8Yuvaxla3Q|Ify~0a*pAHbCMu}&^rl|Q2wn4#rQ@gDAZhnh&IZ%8IJk=c+;q3EAl!n?JIFFw>ybp#^2 z*Co0H!cRM9xrfsW1k-(#@(!h>HQ-dWxv8+Lf&&IR|CDEJR?*?9G%~sX(TAojAs_@7 z1<}h^)BhMP&jc8aW!(FAbsOIB3|q4YejDp(4ZShy*o0_--Qk{+ZPH$g24j{BJDjKdPN9(+nS+3HIHAgN? zUQp{Sc{+s&2soDd)bx1~xNKZk!XONTs;#`uu@rjHt5JdK{?09pFv+HCz4KuJbV1$m zE09YHH1f+EJI?ZuGe zn({AoT&tH-eH0wmly+>#wJbQUF$}x!wZ3q-=KyogNF*hCuE`;ar8Oy+&!y+uqv#%> zYsho$mEx#Q9DR|1A-11aes);}E~A|c?i)ytIINNyz{Z7(j6=yNVpiZ_+r)!eSE6T)FN9P` z(WOcuhmzn3be-ksoXQ=*KHz#F?fn!l)}jn1ogc1TAWd*;UJ?q8G1ZdtKDeT|Eb6!2 zVWd&?qAybb%3058@7Y|L$s0%CQ(Inr?<8?<-v$T)O}~5~ zIV*wx{-;EG8~YwU!5h@RK3hr?0aGeItCcGZZ9F@FC51Xt+20LT15R^Qb}X!7QO!%R z8gSax4ot;(Fc~h0ZLhPzTWhZse=aVo3^~P5s2U7{B49$f7wz3LsfIrdEEHAii_uoA zca}8PBrM1|Gk?WkZvj0IE6owej5zf_Y%8Oi_oM9kmgGp+L$qQ8NVObEB!<71vsW16 zW;)C~&nrSvL$Lodm2Z<~0E8sKW!P2!bLX^8 z*4_KHGd)&^K~q$P-#w{PSkU=8^sdii;BPs;%Gl9>aPX4hV|*>QnT0$D8<>Pa8&W_7 zggFT@jy3_N8qO^#TQhU9xdOv2MS3sjz4}B&suJ-r=Q7Sh=vT2cG+pUBO)&$l2AD1= z70X< z>fHOA`hsoJ8HX(uAOl`0=3ljn)-yItc7w@8%tPjEV}tettM(S_8@2eyoCgQJo^Pl| zA93eu-Q!;d#HsROUC@0#Rz#MPtJ}}@tRuye<_GJ+RUR%L%;Tl%Urn4l47IK6u6E?GvNTIa&p$5Z1$h%F^ z5ba=4@j+=g(o$@>z`!n;m34jZ44vmd^O5xDyN{LI>Mmbg?j@52ZHO-(`(k+UM(;>? zgvmc)moXs3K)e#IRHHjYYq%q10me$byWMaff&?*@aU&+<2ts$w2gI(YwA|*j1y?Ye zndE&o^)CK{dit34T7_1%jHl00z5AaD%$Z6^{V!wDR+)U#c2+Y2gxy}-ClzO{rK+~`qS#FcgHD?0YXw0bMmmYd*#$O>_7e4UDXEvye7s2koB>?@-S zOi=3ly#gksRSY_(`$rjKg*>K=u~XOXSwGX^X5_=#s2FNg25&)HC};U*mz4Gf@x>Su z3?IGjhmrFyp@ZTbks`yp-0q|;f=TOke9t5hVfZv~xDd+*rR3nbnz(~}4@$v@oF*yU zWPl~RPoa%BWq$rzz!nM4iDzNHAY6?}IABJ&?V&s_=+~SLN2iGv;SInezSj@|uY-QL zB)uft1V}2%d91`9v*a#@37|zp;XV5{580fH&mg=Ed< zq_sILddaaZ;~Y;A4Jt&s%+C2;FmAxb6O0Mu`3*`99&H`?;+1`?A^6 zeA#3h1C>xp;F>-JZdSjnEEKM-`U>9|ZL76DhCVX-NcwUx;YP!$f)}hsgR0wbQLscT zm~mZ=!xXEDs}?R1T$Ra|vT7z})9Ldd+aN^Ga9T(r%^ zXB;k=TX1W8RNyw& zaBMFYL@IS2MY1toK!7i0Fe9S;A*{CcSsE1YDZfa#o3xg2VV(o~LU%L&#;eppM;*tPyrBT zeT*a$;9OuO6oa6^1SY{mS2mzDMOI?lQEx2p3#dS17!MaZ21a1``skjp=eg#ptFDJzuhow@G(o}fV#*6|*& z&nOc(G;Pg7x#nt+U@9N#3R)JToI{>y1&0AEvb~_?w=r4{I5~{mQ9)%kH=QH+i8`Ho zoA9R4jJ`qSXKuVc~daj&-c7T@3}RhQ$1f0Dp_% zFms%?l_ZHU)h<^cM_4Sve`H*sD&95WZ4}>+w;L~<8dr?#X8F$Ret2p^8#S8c>vxs= zue*Q*_;!=qADxn`2DojPr}<}-($m^3jF#K!PAitUSWT%@mRE0h+{Bl$jTm^Dq+ZN+ zkJUI!L(G_=UZFmNnE7x8*pEP5ob6^A4Lb&)q7OJlG8;o@ zD+x7grYZ3%t?wtigF{H;0uDTRLW88BnxPy6^Pr7f(z?W+gaOS86w+i)pJh-xAm z9yGjDfLQXj{4^8NawGwn;5ueP2xSe{amik*YLQx~V6>byJtH(*!)sP+cSzrQktiiW1waX;NS@G??(f3K?PX|! zzmT%5;J}jWNEdQ|t+>3$eO%tt))`;Qga2tM58}3^yv|jXnI=bpF-aEH5!Zqf={2%8 zi2%48*wPQ$z1(;!T4QrgvHkbcd7<@8|8 zXjTC;npic<3{MsN#JRqATu z%=N6*>`zTU)Hq=>;UyyiYWj*j(LG8ty-tB^g+3oFP+E4Kq(U*~<^r^EJa28VGC>@} z48R*Sy0R?>h>8s5H@m;dXcda-IErEbz}D$gn?qu1E9o)J{gMR}a7)g(1>w@urMe*V z$O`{3pKsW+bY>T%pvh5?YWTy zgBD_d2o)qJ`~2=`v&H`4{@VZEZ_gY~7W?D;B?MNwP<{qJv-PYb(Yi=pj?ESA znVbJKSv*R5Tj>Y({=m`FCzQVU2cJD_@%>ON2Vss@FliYM{>J|AI$Dlt%d!8K|M@d7 zAd5xYU8W>SAXT;a)f+zaH>;EpnY>KCcA=(T``_PBf0n=a_jKaA@*XZ8CDt&8Fbo(I z+`<-Dz5tbnlkF@vEK@A@sX5RErnVmgM4Q9_XI_FbGA<7yOr9#Xv5Wu@qzln|_+l7y zqQyiIz4K2KF1RAX)l z%#*%km7+U(r5yAbDs32w^mm))gxbqF)Z?<$*y{<=vWS&0O&TLvkRHo@W1`+HMfHpu zHGA*8rI9wSh0*3x|BU%^Cr_oDQTbe6obmGPrj)eq){NK=GmDD_aou>{NOd#G%>Vvh z4}I*t@BO{|f9|^Omoz0}*+Z{C^Mw!o^*_A-Pu})ViNDrbShh^|O>_2oG&?JVz(jHD z!}S%qqDBL1@n+na@=NY~GfEMUo8HXpCXe(PJF@&kAYoPZ%|*uhLH3y++y_lGXR;fq z^auCt751~44L1VuN&EKB{NAs;<$XW`bw>))N3ko55PA|rHGW9M9elRg!>yvef1%*bKW3x54p>!leHA{P!nr4 z>jpBbD(@O5CaerL*Y=<`#*d7N#e}PE@Ov#stKCB;Qrj1!2@mhFjgDIeYzlt9gbyyW zi=uQ}q{9Vw-epLIV@L>UuP`hZWy$l;5pW?E&B-7ez0 zurnKOpy{sLR;3jL+o}fHbe3kOg&(V$hUNsQsD;99(^aVPdw`1zvTjcg9WOK{fQT>! z=5 z)*L4E3mt5OX#y;5l%9jCUl1F@5G)O~a6C(^bUaI92RtL(L8H|%(v~)3XneW07|5iU z0U1IqIIe&y6fR($S&*ABIu;RHx&X>|kCH7TCM#dzcXz30O3V$?nFg3q4cpBH| zEO403^9F8iPaQZ+>K606nq!=v>JibztmG>OiaX31Xoan${dWQP@6>#^U>I$s&arG^k+7()Mlh0fPNmrE!-e#e4W5jM6i+6gk(m*YC<)+jDop~6Eg--jCsd3Uf~_(b z8zTtzGFl)bG_rEE%1mri>X*5t&~8n2q!u0Ejz9S9X|tOqDXg6I+SJ=9pFp~`Bntu( zn0b)MGOS+E1h>&U_p+c|tvxhkY|p%z7k5egJ3~84Vsr{6oY&GXU7#%YC3upS)yEj3 z`52wU49}WpW@d)xp7P1-pJ)+W-mhEn3v6s7st|@k^ct-aOEQ~3-$>Ko|8xP`p_IqI zdd2aQk{^lfE0{(RpodKO1C0f20F}h$au7eii0BFEio6talD;_xG=@JYfgvGsOAUv| z#u^gCv85Z)i8MNWZ79(INi{%HDn_}i1_yUxaBvp}2X|p`kW+(0U;upp!=bMgLWd<9 z90~XbT5Lk}c;5MbhK45hCb^l3muW!`t?@{@GiN6gcFsim+gys1WWw(LwyzqF<4T#HVSSsDIwJ;r%T$;3TL06IB1VvVnFZ1U;URk>fp{{R-f*H*No5;Pg z$M%Wb#U2XS0GiYEZ2lHE3{oDPcE3Gwu$_yjxSW)W9T{-GXIm#);sw!O6CqJE2c^ zYI#+Zrh_Oft^r0&W(Tt0K?0orFt~q^dvoS7`+Mc9v7fLz9n<=1yOUqoD`mRJAAR&B3XoSWWJTr`V+0rjWLX;-inPJ79d1W^Cid7( z$J+~Dxd8IY1<)%+C9;1UqFLQLwd^9|khb0E{xOd}C44bYcB&7FObn2pmI#2F)SFo| zgtjKlIBu}WkC<~23^L~iUGR7{PG-Hsnx^ysZA9wopo30)Dt494J)Pf8D;2&4Q?sgu zVPfpGe3ulQO1q?(*vY2aq7s`8Kss?RR7-oIz(&{$1%WZVdKn}L{|$Sh3>06ZP;GHf zl-lZ?*0`He!k(x>iZl}203pj1d!jx*0G?>BM**IRptg81W&}JPCg2IQTL+#tVR++g zq_C%}m8TOoz0VAie~E9|hEuUePI+1b6oa>7^8ssxjuR$~sI+`Fk7#k$N;E|& zAgxaM7FaETKQ}I27Y6=(`bA@Oto_RxX`07}`n3rQ$q^&xPl>a1AFv%GdH2)Vl=+BV z@4TEW>HL*w<7I0%(C3&32x;~hMn!pKe_hwCQ+`cXRD)c)J97u*9bhaY(V09a1Bq@6 z2j&7f5Vsdh87}JL7Mbs#!O_rE=uN3b(x7lgV+}HA*`bF%#BdkXpylC&RTg?O{=k=n zK$Ji3o_z8T6^j~!4w14Gpih_|{2N~s1O)ak3J$Mhplgx4)ns9vCTC>&S2D@IlXL$K z-SfV|y{Z#BR0nE(gQD;@;(^BK&^YM;l^o=DAP0FcIf&?UcXmtw3O_T>wpx6$Saf0j zvPWB5o93Ct3`=FB#ThQA7|O7QX3P}J&Zv}JXzgM%fQ-f_ zgh!1Q3mPReG?sFeVtS@liqf($&5~-UtE%YaJ&b(P6r|#_O`tnXT4!4J%G`mCfGTP*Gr3B30U#=TPvkFJV^;2yVZcLmpbGoLalq!2F{gz&O+v^{ zUu%61?3MRF>3$tJClyT`T;xi}iImOqo(d*9hX(dDTi=6wfdcLG{!*GyR8kgbS{c&~ zs0m4!NbllCv}Pkyx3;`UsI@R(&LcN0TxheO@}94gdwsd@e{=aI4mAG;*Wbv($DIz1FCbQnkQ5mMCi)$v4 zYbN5FhOCN5iao#`Q(fVXLWa1bb)hb>8{<(l09H$X`%B8Kihz1}OGd~M)&|Qh@Kg?; ziPt0%cwGah5o^;L(Gu2{i?zWlgdxjsj^z+2e3LD?cx?ya@{ajy` zsBiIe^#}@X*Q_4cKAm)KYG6IHZtgcVX6X3fS)Xgz%a>kix}SL64qjH{h;zuz(GdS4 zP)EI}nB*`Px0a9n-2o9=^TM?f#s`oGi|`z6vck_E899;(jRCpdF6B~%Ohcm8T&jkO zQ_kSVP5-rrovFqvXR3=RVbhOt@~Jq|*ub3%|0c1)F>|K^4sjA@^K8^x9%2|NIq)<( zMvfe{LgTg-9ka|ypkT+|T zsYpzA+-+Zmz92Iga~f7n!OFsbITJRdwIXmeq0Y5JL@GK3Qh5z5`L&JU7Bi+PL$u_eN~l9PMKoXs^sDjZ zi=}8~C|W`Z!Hh+`LQWqvN%p#&rnl5zWlziBW2_FFUN?q*U*xPVPiV1uEUrP@lNHX6 zr&dWI?lIiA@-;KbYm0F$C$smJWnHZwH!hJlLOJxgepf^O(Pm zZfySKTJx{A-fBSy4kx|lBMx(IO9Z24QFB{0(=VcVhcI+>OXNtMTGv+Lq_bR&>QI#@ zqQ})-OK55#Os#YW{gQYfwl6rbI~b#?Mm+GkOwC7T%zcSJn&AnP$~_NI8o1}3VNx)W zSIQ;o44Z%eZbQC;a0mwZ9MxKe#ePfq##=4+jw=VA~wW?8`Bg>a8gLhuKH$=SzIQ)>~#DJVa z6>_zf2Lz z1iIZ^C>9}J5H5-}s^!Zy2u9y{f%2t|7ulUNPo_5*Pcr$)uutdp(ds|7A+MLzb~c4RFO}K2UaW7t$N;pq z4}+J2)$OhJl`9ytFbch+wYkLJ|Q zQqs&BPn_r!aEFA@9w4I2v=}M)6{aw)oI%&uw&=!&q)o+Wi<&mtQ1g3eCaeUhZ&|I- zrkav&6~UNu>pO7=;~elZ<85=T85(?ID)&3KdX)RgKyDNqk!Vv5w6A}L_a%$GRRe7f zrrL!{s?#Pd#`}t20RuXe1>8|@EOeSM-4s$alSGbLOzbWB)urfqV#HN_znw674)(Wqxep0S@ty|s88ys3P(oQzN3&p9u>?zA(ME!+HqBG{*W11Yso@l&R*NiP=bBOR zvAM*k*Hk4e))yIvs!>?gPN(xj@Q@4y(QrWm!BdLlNWZD6tze?=AU+@|tsD8Q9gH)z zrJ0@Ilxm|wSm9eCy#sC}Bo8%~l?6|s3&yAlsYxwr_n7Lyf}-Y|>ZKN#awthg^U+?I zBtT#2is)$U4xuD0uv+5Dm4RV^8dC}joF_CsSFX`UR5@W=Rg#3`Oy+rJrKhpr@fPhH zs0O?-kr6fovlR=nOkIu3)Ko1Kg>3EdQu^ zN#_k|^V))na1MR)$rU#U>+!aEt-$2D*w=4eOA5Htef!!s_j!3EZfMA5KBi%p+$rVZ zT9DJY(^kU7`ash8qZht<^Odu&o!xcy?CyoR*=x3K zxoXS8{Oq3D`Q5V@UUvDbc3*km*mBkEj;j|I<~MKO{Zq5^3p*~|e8m;>v%7b1zG}zS+ZU1~c~#O)+FZ}(+TqHy zGMVB^EtmMmmu=f|`J4*cy|DSJorCu?dJjxnc5m6S{SC8Qu6)D75AE2p{fgP`JFZHS zamvuYl-~({RrVym_4lf0n%@=tcKL-ZLJ8?Kn&{KlA)yfy76rvlSuTm|zFb6vyrySNJW%QkPHyZq|i3p=g?ZF5_; zUwK6hcwWr|_w3Hi3vbwR+2wECy!$F^Pw4Oil+mD!`?!vA{RGz**H3d54nNOTefCwZ zIoC(IDnET=#RPKLxnq6-lGsMYkx+IgKa_b{Kg?D5KQ}zj0Iz+#dE2&2tq(7~YIb3> zh-l~LE4OTily-RER_~Sbvd!BzZ@+wYcffUgyn5%(ZPz5fN7;h^w?iH8<0|-nj;s3p z8m_|KkH_|3zT=A7OSf$QsU3cE#pOG;L%NsK3VRnGR2N;b`>M_J3s>#F5*CDLHVMgAM+lt=2d+x=&OesF;so-h%f@9>ANpe^RIB!Q0BX+Lv48rSJCed zuA=kJT-COp;HtW9=+Oj_qe#LGLoi_=_Ewl5*?rU~0%wAQ@ z&d=|dKc}Faf2O=uTw{h=oe9u_;uTWfJ4GuJ=LS8{0(d^|kZT5=d^{<`X zef745bI!SX`y1ys?_7W8>x&)Ri_P1M*Pk~(|M~*tTs>=b@~P3=YOZIgYt9mffkEv) zYxlwxXYHQ9{H)nGiQ0C*bbdE^-a|b-uD`&q>Wk0+ZRGi%MxGCa=Y?x_&R%-;{5FH& z${l+y*s%wWw`a$~?4@rsJ~Mm8&iNfXckE^`Z@FT}P9b-r{=gs!nH(nZOZp(H?=k|pyy!{W`HeWWojan9JFK6F0 zd->H1voCAb>aDTuhl>p*+jm?lwsq;A*@YdOFQZjkwr}5Y&Ft>v znevx$VAc3~*_iX6Gq{T8^KktMu1bF$*Np4MT!n)l;;OdS`8Vwo)r0k`uDW{rmW69B z-MM4Owu;SGqcHO3*#&FN5D#9_a$fsSlz$54e~GJP$Bzdh8KA;x#EECi6<2QFeQA)W zu&GOTY=7-6SHvQt;m5AN4AAVw#fVl(+^a8#!R@x8xOv+fH(#^+=c!kG?Oj~OcizEO z?R;x^-Z7UX_i`^B#5}Rw-8-SxS<2nMu=~8Lb}n3Vo^D0)n-S9zZnL|~c*g*>?3B}O zOF||lV}wibd$n2PYc0Q<3$VL$+vaPEEm!T_HhUF?8p|%`XBQX_40i^$wV}9rJEL{> z@`c$e;L&v%yN+_snn!3|e%ANTUiSYLcO~F)6j!>hIW@X`$hIz*jj?1~np-oYu`M66 zWebEPTb7LvER8fh(imw*%zCd%wK#8H^AOf16YSqmF*n*W>agt`J&6ySsqaMF&NvW|BOgJ1K zO%H{`J(xUnq)|GZ%sGTB!r^??d9sdFT0TsGE-llkU${d;rv?Mk3%S-TTSt$1*!s~j;qlytqmh+0*Dt+V|_CG$zV2>g2HCnaD<1@KETJr zJLwyp+>JB`%0h-pG+a@NE6K_Zw4wEn;Yv0MmC~zGMtmNe+DsgG>O^$CI@P8_r@0N+ zd_27idD7oIber}IU{Ufvim=kOHYv?d74AemvV$3QZ{~j7Q{P?risJ;kdYZn<+iOvE zAd6|jIh;P0d|fhzO|uB))Q>UtI*g6R#CI}&pz8*B)1Q-ITWR%JCduGEFoGE@3ELhU zNsfOQH0%Ur!}_{#??$4P{;1a1i?;NkUH*@@zHfsw`PO#?`87vw1V3JG$m7Q-3{{-u zemYa8nd(VptGOkU2DyiODNv8^VU9nX6)(`wE#M3Bh*p@A56O?zgp~iBcFRXaE`uuVUpcff&4I+e*bfwfGifioS4CEfHbC4XWv@@P;48%Nuj^2TRh^NWz_QYJ8k!W-~ zy&k7m^Bdt6M^(;@YthFJ^wEvfh?Gsk`cLjsHa@H-7&;!zjsV!gS`NUhjHrpB%rHDm zz3n!%BaZ||M;(HWHTL)kT4!Sjh%xG;T{mI9TiQZs8$_ZA4#^wkKY=+To}wC}CR{qR zOxTTnK83`PjQlw6N$Y-W*~9w4VTT4xC5X|ES!F^O=za%6vKUv2Ykt5_3+k=%HwA*B z=J4_rEA>`_D9MV+Y_ZzxMULW<(z5ayGiS}Nm@{{tR-v-0x~6tMTd?qyMW-&Vt6#Eo zSwo}K<@R`eAF$g`w%VGtt?SmeZP?g;+UXrbS8W5_}+cz(cm>cEOTMA8Q{bKLBid$H5AmFNFx-6$O!x|j*}UI@GyH6 z<#WONULD!xhkIT{8OdK~lEL*HX0$;F5h)d#6`p#o#lxtq8f6qoYehI1n1Udc3XGyV zLX5=|VHQFiLR4M2l1?kAi{Yg+L@SDNLWoAalSF(*5xaEhn2qn>X0#z2M*Aj=bSdbN zeAU4XUWIG#q}$1$X$NR`##l6&p@@-Dw-|LBke`kW$A^<6>Q)Lz!GI^(KzwL=d5mI& zhyg`Lrp;*-iXHF@elMGX3b&Gsd;xJ$4s)_$^TN*#p~L`}pKBT*;oNJ4cYEDa}! zZBR2@lX76I#rx7=RdSS9Ku-on9al$2AdH421N0J(9Zgb{!O41XrL|0E0cxRmQ&m<@dB!j zHyG0-k|`Cq1?ZYaGoTJf&W+O;FqHfmIoXyZL%cA9#o&$k3^S=@c3?zhFeW64i3TEfzR>iE_W+k1?C>BCl=eR z65p$G=prbUn)g6HjKAPO6!;!HuH33PZ1;+moY|kO=0WLgS&v0Ig_Jk#jd1s+aNZ%OwtMt4MMK(s# z!)?hFR4n_zT?lWZkL7tZ@6>5(x{?$W^CI>K?GOd*fgDfDCv!VJO(!2bXm(V?cgUlC zN5S}iR*?Uxp5F|3i2XT+b3xi>IC4Du+STT{j(D@HrAJJimwvwTG%H{Ga5Ub6xHQtBW<#eHNsu|Y6aXn;w5 zhX@CZW0<+QYVyDd97cQcIgIw{_z+IWvamN0T`b#Sl#_io%7?L_dXexb%4SZD3CqJr z#m^tScuw|{60N1)ezQJ2n4id~{;bF7QWF&Y>6GNOlEOk{1?)Fw4Vz!9*}8S{bK{VQ zfqm>e1VO^AAJ54qb?H7aSS0MlGtwa#AhshSE0gC+gkcy}5iUg?!W3V{mF%Wgm*58> zbS!$310MDrloLOUdfc?da0DF{1oBJib42g2RW}!yGloc@9OHyXp^?*~%hdVbP@nYM zB#+g-P~a4M4zq^&8iq2;=oph@{qUrFvyuTcWFsRhH=-`#mME?i)iBzuB$bPiAHtF(IOdquLc%q5vi59n$e~eSJDRtuRu46 zlSCCRD^_Lt90;rNqD0iAU%l^MCr)A7*w&&Q*BFK%YkSSuY{J7B17XHr;7anAzot{; zNkrqCTZ&){hvrjR4b|gxkK6;O4b2Uh%12e*t7nsBz0c8&0G#z*c+S3WuwEcqo&+wdV{@O?e z-VG-yyo6_TN~#mn#6nYSyc+QZhibyiQ#3tu4eHZ6`oKdsQX|q*q&lQUNUKqgKBx6` zbuuVl7-TwVjIc=5C_5sKRKbs{?r*c`!21ssZvM#h|z4GEo&4h0KgoMlRJm5INYUfc{haQ@zg;3JR%Y$KnC5{ z7;<(E>>=bzI)&^fU@ugecE)D#9tWsgS@M6lv2_|nw5g4I&Fz{jQqzMGDDpJP7vO+% zy?!dF!PLnK(nz?$MZbK!+AODP16^}}Q$kKf^45F96SK_Vx&dvTdSQTtPoW+VFkb3~iJq~t}L zp+%+#nvE7dv{-^fpS=1ws^D(`O>fkRfegdkujy%RZ!es-AS|fUP@qBkpFxu}?kC9w zJ#Z|XiM|KWm*FiL`3vxjEQ*nzz&%Ae)@pG`?Ccmv#;>9MCpuQFr5<|ZyHlwz69zGk z-y(7E?IWK5Pe##sq#N&zjgfA2sn9uOU3rN2Q|N0a`f>BV)*O8b((z_>-fF)~IzHx# zohaVSW3NMm;qdm*ST=>%h*XMW!OHP4&HGCqM(tx{r#KTywUK`g z_jKZG)PaEl>c198hND--r&3^hpP2N-!L?uk!Ez7_YhE=K+g+|#^` z{8rr0&dYDdy(ceEJDd>FWO$ClE;vKvmLndJO{CNaEIviVXeW?=wW|S`3T@gExWW4g zC<<%Q2p&*EuuX+S3~UgBouTNB;iPHEYH%1J6qtujTJah}Tt8#cVod3SpuGjOjq!g5 z_q1+Cp5!KfzSkj7>tvLF75B7`|5y6K(C!V5WkLe|l3zt~Yvfns-c^t%IW@{@eq`bD z^DHm_S=@&U@?=Ae`Xu+n4DP~K>x&R;1JRDbVgQW`i(J#=IUL-l_l*t! z6#;(6ViYmQrdok|w9mS6B|6)2g~}4v8=xC+E*MyxOL&9@8VBMOY1U`&6f$VDEN=`X z_YC>NcuqVkq}`5Ze*)`F?U05Vw8{G|2aAV5slbe4RJ-F&bBniu(n@ z$TQR<-`2=~%yrSQp2vxppxb9)JWc-L?8C(aH^vYj9bAomX^o!2l zZ9+oymA`HLLC&;!+>h~h3AH#0c%mzo7#uG(3VO%TFX_56kH&A~4MgKrWZoLO)s1qB zIrUQW4-Mbh5NGV&{tC;PY=iF{+4TMrV=)mT%~W4%bEU#Wa6 z(l(_0I%gtJI+>o)hh&a;M`(!JP}+rb780EW=Rfa5-WWTd8($RqTZD7fL5v+vTm*{( z*HsVRp}yOzo%7GamF8u}JWRMo^dKZZ_TjH1yzlFxd@N|n$4s=|J(k#L2III9eG$K- z=!@a{#)IFVHjjQh<2FKb`KOgdP}YWnCyF(Zub)ExL&%MOo;aS&;{7>zkrdRVnZoiU z8hM7?V7(TdGT?6q5I2VLib0wwOwS`=JXV=kYlNPjxRznh_-SIHyET}93QH!JUPa)i zPTIMY=9DdQI)&f+v^@^PjF;iT{y}iD{ zzLVECMBi z&>VCJJwb2K7xV|4f`MQ#7z#Fr+#yfM8}fzxp{7tE6bywz&CM8MGrDgE>1H%*#-j+m z1vW#-Ay+(cNV1^4U8u3#a;U2W1@jrqq*+}vK`6H~kzu`=oVJ09r~P>QJ*dSt-^7)8(2e~;dvpM2 zV+pomB|vzT)zi%q?KLH0D1{i&c2P)+26%BLSqk7vyfdJUT|;UhA}GYndbLF;l{$(CJ>E8z%(_Pb>b?-A*8`Vi{U9w&d1e3y6C)gzLw zF`UO_$gO~IqTW%oBV0@8N@Pond?oG!NP;MvOlGrWFuk?D8wGy6xWkzW4AWkNxC#FTH$RP|9a4 z@%V$`)WGh?!Y(hf8fDqo;~`9i#~J7&9^-8;KM(D z;_pZQtGZ`OB}k_gmk7@ZTT#@w4R>b9V0f^IzUMo*O;qch8s1 zPb8~r`Y!nNU3Xvjz56TX)Xs0)(Ajn7j$OMyec``7{PZ*bdGrr&rP5bqvR5y5x^BJu z+YkQuiD#d`ZuK?Sy04i3A5TAiyt8Y^PK&j)tj_iN8;N9a<*K#o4_?_blzsHEC!hM& zuU~oRxWM`r?tfm{zs_2vn9C>bEXmzrns1w^lIK}P#ijTai!55qmU4S{=?qJ+MOLcq zHrXm$@Esnq>`+W{ky$L6ZR)gCS+-du^BhOF(keH~qEc=yb%d3gQ~TJcvgg#?qo)1$ z$d%^(f0wsgDr|FYvmCP=d(3uorFpw$nW@d*fFD>9WlvFqQfV%db9bW1st}AZ1;a|?besg5!7C42?8{qX z@hh$>Pxd|d`Wrh2-u&C~o-NmX+3BjQ@4f!ULtnl5*27=F@BW9(MUL4u;Z^H5-E!;C zetx56Ugg45TUNdD+8f6oenerXoVvK)7Yc7Yt)siAcPq(W|DYN>JH7XU3opL;_Pg)- z!IO90ok%|Lh20C!H_1w)9Fs+tGq=A+_LNpDi)^)~Wu|pX$TI0| z+A8eUxy#o#%Y#;%y8_=+Rb>)ahm_MzF2!!KSyr<;#bFD`VN<0=aag+BgT7*)#c8!q zEZ%(jGV9Wc%Ei^Q=GZ#X!Mfsk7Q1<)wa%6;THCVJyxe3rZ!(LfGTD^7WT1AV)tc60H}u-P7HQ0C;myCT}-*l4r2t*_c>?I~`z*mHkwv)9NQ+Jkb5)oyOK*e3$> zEX(EUtzxOS_@XbzvPHRvF76mCKHx5^xZ?Kx8xDPUf3sz&vdg^K-e#{i&D?*_PW5!9 z*;2lmMBfd0?tjPV@p0M)iRr#ffk_IK}*lN$+6{;z2P;A%{=G=7`{Yoj9i{){p4?kBZmO7LW zCRcA=*g3JqQG>ArtR<*wv*dnys{MfZq&i&J<$ZLB4mD1%dm#X?=Hr_&sBVtiCjmST ziQ>_|>=^#$n&bUGpo{64=p3~9W=k25?{(w8J}*zc5ZOvW7KDowCR}Oi7tWe_qcCF* zo9|%#^WSK=aoJKgYe?R5q(M5|-&lLB-zmJq0yiA*5ByzxAt2fp1Q!**5WJ%#((Iah zsM%c|+4!g0LmjLAk?x~=4sGg6F4%ni{f9OSPegjurw;W9&n?&@9C@Mlt`{TQUVCZ5 z_9tIGw4DjBZ$BztxI-9&OWp{;BH=%AW08AynW#eBNs_3XBGy*zEDGCf;#@_vK{=R~ z$t$c&=ZY+d28tD0&0?2o#4t5itf*p_Dn&_Zh89sIXi>3N!mor;-h>L`EU5xI2DL%k zDq3W_R4Xn=TL)U!gFL9pCa55bRK%&$kkF|_`D&>d<1>1x5jTnoUd$CmtGG#&EDq~{ zDA|fE?NSx!iDIxsM31H-agj}oDWVyJlIBT@T&Ca){v@+lDuVZNjZ};OR^xjktfEw8 z6QSG1th7)(S5_pOXqJBiCSbG{q9|F-c1d*4_b6`UO=3NMn~`CXq8vgY8p>g-BwZ_u z#iE5el%+>j3*wI!2=ZlOKNHMxNx<*wGO1ev3c%RsNha|csd7fKxY#EV0O@A6aQK zbBL>0E2<|-|AVoaajlYit@LCM@dKr*j72pGHc@&DD-Vef528OsWcGS9Un#RBJHc=O zDb(IvfuVrPd1iC~omhFl?pgu8MO%gxue> Date: Wed, 28 Feb 2024 15:30:54 +0100 Subject: [PATCH 42/45] Add DeterministicError type for redactError --- x/wasm/keeper/keeper.go | 10 +++---- x/wasm/keeper/msg_dispatcher.go | 13 +++++---- x/wasm/keeper/recurse_test.go | 2 +- x/wasm/keeper/relay.go | 8 +++--- x/wasm/types/errors.go | 49 ++++++++++++++++++++++----------- x/wasm/types/errors_test.go | 16 +++++++++++ 6 files changed, 66 insertions(+), 32 deletions(-) diff --git a/x/wasm/keeper/keeper.go b/x/wasm/keeper/keeper.go index 393a9bbad3..9844f8303a 100644 --- a/x/wasm/keeper/keeper.go +++ b/x/wasm/keeper/keeper.go @@ -324,7 +324,7 @@ func (k Keeper) instantiate( return nil, nil, errorsmod.Wrap(types.ErrVMError, err.Error()) } if res.Err != "" { - return nil, nil, errorsmod.Wrap(types.ErrInstantiateFailed, res.Err) + return nil, nil, types.MarkErrorDeterministic(errorsmod.Wrap(types.ErrInstantiateFailed, res.Err)) } // persist instance first @@ -408,7 +408,7 @@ func (k Keeper) execute(ctx context.Context, contractAddress, caller sdk.AccAddr return nil, errorsmod.Wrap(types.ErrVMError, execErr.Error()) } if res.Err != "" { - return nil, errorsmod.Wrap(types.ErrExecuteFailed, res.Err) + return nil, types.MarkErrorDeterministic(errorsmod.Wrap(types.ErrExecuteFailed, res.Err)) } sdkCtx.EventManager().EmitEvent(sdk.NewEvent( @@ -485,7 +485,7 @@ func (k Keeper) migrate( return nil, errorsmod.Wrap(types.ErrVMError, err.Error()) } if res.Err != "" { - return nil, errorsmod.Wrap(types.ErrMigrationFailed, res.Err) + return nil, types.MarkErrorDeterministic(errorsmod.Wrap(types.ErrMigrationFailed, res.Err)) } // delete old secondary index entry err = k.removeFromContractCodeSecondaryIndex(ctx, contractAddress, k.mustGetLastContractHistoryEntry(sdkCtx, contractAddress)) @@ -550,7 +550,7 @@ func (k Keeper) Sudo(ctx context.Context, contractAddress sdk.AccAddress, msg [] return nil, errorsmod.Wrap(types.ErrVMError, execErr.Error()) } if res.Err != "" { - return nil, errorsmod.Wrap(types.ErrExecuteFailed, res.Err) + return nil, types.MarkErrorDeterministic(errorsmod.Wrap(types.ErrExecuteFailed, res.Err)) } sdkCtx.EventManager().EmitEvent(sdk.NewEvent( @@ -590,7 +590,7 @@ func (k Keeper) reply(ctx sdk.Context, contractAddress sdk.AccAddress, reply was return nil, errorsmod.Wrap(types.ErrVMError, execErr.Error()) } if res.Err != "" { - return nil, errorsmod.Wrap(types.ErrExecuteFailed, res.Err) + return nil, types.MarkErrorDeterministic(errorsmod.Wrap(types.ErrExecuteFailed, res.Err)) } ctx.EventManager().EmitEvent(sdk.NewEvent( diff --git a/x/wasm/keeper/msg_dispatcher.go b/x/wasm/keeper/msg_dispatcher.go index c670a23225..e663b9d393 100644 --- a/x/wasm/keeper/msg_dispatcher.go +++ b/x/wasm/keeper/msg_dispatcher.go @@ -209,18 +209,19 @@ func redactError(err error) error { return err } + // If it is a DeterministicError, we can safely return it without redaction. + // We only check the top level error to avoid changes in the error chain becoming + // consensus-breaking. + if _, ok := err.(types.DeterministicError); ok { + return err + } + // FIXME: do we want to hardcode some constant string mappings here as well? // Or better document them? (SDK error string may change on a patch release to fix wording) // sdk/11 is out of gas // sdk/5 is insufficient funds (on bank send) // (we can theoretically redact less in the future, but this is a first step to safety) codespace, code, _ := errorsmod.ABCIInfo(err, false) - - // Also do not redact any errors that are coming from the contract, - // as they are always deterministic - if codespace == types.DefaultCodespace && contains(types.ContractErrorCodes, code) { - return err - } return fmt.Errorf("codespace: %s, code: %d", codespace, code) } diff --git a/x/wasm/keeper/recurse_test.go b/x/wasm/keeper/recurse_test.go index c5676be659..a0a2bae54a 100644 --- a/x/wasm/keeper/recurse_test.go +++ b/x/wasm/keeper/recurse_test.go @@ -264,7 +264,7 @@ func TestLimitRecursiveQueryGas(t *testing.T) { expectQueriesFromContract: 10, expectOutOfGas: false, expectError: "query wasm contract failed", // Error we get from the contract instance doing the failing query, not wasmd - expectedGas: 10*(GasWork2k+GasReturnHashed) + 3124, + expectedGas: 10*(GasWork2k+GasReturnHashed) - 249, }, } diff --git a/x/wasm/keeper/relay.go b/x/wasm/keeper/relay.go index c68171b9e8..8be2c287ef 100644 --- a/x/wasm/keeper/relay.go +++ b/x/wasm/keeper/relay.go @@ -76,7 +76,7 @@ func (k Keeper) OnConnectChannel( return errorsmod.Wrap(types.ErrExecuteFailed, execErr.Error()) } if res.Err != "" { - return errorsmod.Wrap(types.ErrExecuteFailed, res.Err) + return types.MarkErrorDeterministic(errorsmod.Wrap(types.ErrExecuteFailed, res.Err)) } return k.handleIBCBasicContractResponse(ctx, contractAddr, contractInfo.IBCPortID, res.Ok) @@ -110,7 +110,7 @@ func (k Keeper) OnCloseChannel( return errorsmod.Wrap(types.ErrExecuteFailed, execErr.Error()) } if res.Err != "" { - return errorsmod.Wrap(types.ErrExecuteFailed, res.Err) + return types.MarkErrorDeterministic(errorsmod.Wrap(types.ErrExecuteFailed, res.Err)) } return k.handleIBCBasicContractResponse(ctx, contractAddr, contractInfo.IBCPortID, res.Ok) @@ -201,7 +201,7 @@ func (k Keeper) OnAckPacket( return errorsmod.Wrap(types.ErrExecuteFailed, execErr.Error()) } if res.Err != "" { - return errorsmod.Wrap(types.ErrExecuteFailed, res.Err) + return types.MarkErrorDeterministic(errorsmod.Wrap(types.ErrExecuteFailed, res.Err)) } return k.handleIBCBasicContractResponse(ctx, contractAddr, contractInfo.IBCPortID, res.Ok) @@ -232,7 +232,7 @@ func (k Keeper) OnTimeoutPacket( return errorsmod.Wrap(types.ErrExecuteFailed, execErr.Error()) } if res.Err != "" { - return errorsmod.Wrap(types.ErrExecuteFailed, res.Err) + return types.MarkErrorDeterministic(errorsmod.Wrap(types.ErrExecuteFailed, res.Err)) } return k.handleIBCBasicContractResponse(ctx, contractAddr, contractInfo.IBCPortID, res.Ok) diff --git a/x/wasm/types/errors.go b/x/wasm/types/errors.go index 724c0c38fa..21b4683337 100644 --- a/x/wasm/types/errors.go +++ b/x/wasm/types/errors.go @@ -10,10 +10,6 @@ import ( var ( DefaultCodespace = ModuleName - // ContractErrorCodes are the error codes for errors returned by the contract - // Since contract execution is deterministic, the errors are also deterministic - ContractErrorCodes = []uint32{InstantiateErrorCode, ExecuteErrorCode, QueryErrorCode, MigrateErrorCode} - // Note: never use code 1 for any errors - that is reserved for ErrInternal in the core cosmos sdk // ErrCreateFailed error for wasm code that has already been uploaded or failed @@ -23,10 +19,10 @@ var ( ErrAccountExists = errorsmod.Register(DefaultCodespace, 3, "contract account already exists") // ErrInstantiateFailed error for rust instantiate contract failure - ErrInstantiateFailed = errorsmod.Register(DefaultCodespace, InstantiateErrorCode, "instantiate wasm contract failed") + ErrInstantiateFailed = errorsmod.Register(DefaultCodespace, 4, "instantiate wasm contract failed") // ErrExecuteFailed error for rust execution contract failure - ErrExecuteFailed = errorsmod.Register(DefaultCodespace, ExecuteErrorCode, "execute wasm contract failed") + ErrExecuteFailed = errorsmod.Register(DefaultCodespace, 5, "execute wasm contract failed") // ErrGasLimit error for out of gas ErrGasLimit = errorsmod.Register(DefaultCodespace, 6, "insufficient gas") @@ -38,13 +34,13 @@ var ( ErrNotFound = errorsmod.Register(DefaultCodespace, 8, "not found") // ErrQueryFailed error for rust smart query contract failure - ErrQueryFailed = errorsmod.Register(DefaultCodespace, QueryErrorCode, "query wasm contract failed") + ErrQueryFailed = errorsmod.Register(DefaultCodespace, 9, "query wasm contract failed") // ErrInvalidMsg error when we cannot process the error returned from the contract ErrInvalidMsg = errorsmod.Register(DefaultCodespace, 10, "invalid CosmosMsg from the contract") // ErrMigrationFailed error for rust execution contract failure - ErrMigrationFailed = errorsmod.Register(DefaultCodespace, MigrateErrorCode, "migrate wasm contract failed") + ErrMigrationFailed = errorsmod.Register(DefaultCodespace, 11, "migrate wasm contract failed") // ErrEmpty error for empty content ErrEmpty = errorsmod.Register(DefaultCodespace, 12, "empty") @@ -95,14 +91,6 @@ var ( ErrVMError = errorsmod.Register(DefaultCodespace, 29, "wasmvm error") ) -// Error codes for wasm contract errors -const ( - InstantiateErrorCode = 4 - ExecuteErrorCode = 5 - QueryErrorCode = 9 - MigrateErrorCode = 11 -) - // WasmVMErrorable mapped error type in wasmvm and are not redacted type WasmVMErrorable interface { // ToWasmVMError convert instance to wasmvm friendly error if possible otherwise root cause. never nil @@ -164,3 +152,32 @@ func (e WasmVMFlavouredError) Wrap(desc string) error { return errorsmod.Wrap(e, func (e WasmVMFlavouredError) Wrapf(desc string, args ...interface{}) error { return errorsmod.Wrapf(e, desc, args...) } + +// DeterministicError is a wrapper type around an error that the creator guarantees to have +// a deterministic error message. +// This means that the `Error()` function must always return the same string on all nodes. +// DeterministicErrors are not redacted when returned to a contract, +// so not upholding this guarantee can lead to consensus failures. +type DeterministicError struct { + error +} + +var _ error = DeterministicError{} + +// MarkErrorDeterministic marks an error as deterministic. +// Make sure to only do that if the error message is deterministic between systems. +// See [DeterministicError] for more details. +func MarkErrorDeterministic(e error) DeterministicError { + return DeterministicError{error: e} +} + +// Unwrap implements the built-in errors.Unwrap +func (e DeterministicError) Unwrap() error { + return e.error +} + +// Cause is the same as unwrap but used by ABCIInfo +// By returning the wrapped error here, we ensure +func (e DeterministicError) Cause() error { + return e.Unwrap() +} diff --git a/x/wasm/types/errors_test.go b/x/wasm/types/errors_test.go index d01578e7af..45d98c9299 100644 --- a/x/wasm/types/errors_test.go +++ b/x/wasm/types/errors_test.go @@ -94,3 +94,19 @@ func TestWasmVMFlavouredError(t *testing.T) { t.Run(name, spec.exec) } } + +func TestDeterministicError(t *testing.T) { + inner := ErrInstantiateFailed + err := MarkErrorDeterministic(inner) + + // behaves like a wrapper around inner error + assert.Equal(t, inner.Error(), err.Error()) + assert.Equal(t, inner, err.Cause()) + assert.Equal(t, inner, err.Unwrap()) + + // also works with ABCIInfo + codespace, code, _ := errorsmod.ABCIInfo(err, false) + innerCodeSpace, innerCode, _ := errorsmod.ABCIInfo(inner, false) + assert.Equal(t, innerCodeSpace, codespace) + assert.Equal(t, innerCode, code) +} From 3e960ee2a658877d2d773a1ce2c10ca02390f866 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Thu, 29 Feb 2024 15:59:15 +0100 Subject: [PATCH 43/45] Fix DeterministicError docs --- x/wasm/types/errors.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/x/wasm/types/errors.go b/x/wasm/types/errors.go index 21b4683337..00ea45dc68 100644 --- a/x/wasm/types/errors.go +++ b/x/wasm/types/errors.go @@ -156,6 +156,7 @@ func (e WasmVMFlavouredError) Wrapf(desc string, args ...interface{}) error { // DeterministicError is a wrapper type around an error that the creator guarantees to have // a deterministic error message. // This means that the `Error()` function must always return the same string on all nodes. +// The DeterministicError has the same error message as the wrapped error. // DeterministicErrors are not redacted when returned to a contract, // so not upholding this guarantee can lead to consensus failures. type DeterministicError struct { @@ -177,7 +178,8 @@ func (e DeterministicError) Unwrap() error { } // Cause is the same as unwrap but used by ABCIInfo -// By returning the wrapped error here, we ensure +// By returning the wrapped error here, we ensure that the DeterministicError inherits +// the ABCIInfo of the wrapped error. func (e DeterministicError) Cause() error { return e.Unwrap() } From ad93ad3dda19649219057fe14f13591b98a032d9 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Mon, 4 Mar 2024 12:15:27 +0100 Subject: [PATCH 44/45] Add contract error integration test --- x/wasm/keeper/keeper_test.go | 62 ++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/x/wasm/keeper/keeper_test.go b/x/wasm/keeper/keeper_test.go index 084d8d982f..d6336521a7 100644 --- a/x/wasm/keeper/keeper_test.go +++ b/x/wasm/keeper/keeper_test.go @@ -738,6 +738,68 @@ func TestContractErrorRedacting(t *testing.T) { require.Contains(t, err.Error(), "addr_validate errored: invalid address") } +func TestContractErrorGetsForwarded(t *testing.T) { + // This test makes sure that a contract gets the error message from its submessage execution + // in a non-redacted form if that error comes from the contract in the submessage. + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + + reflect1 := InstantiateReflectExampleContract(t, ctx, keepers) + // reflect2 will be the contract that errors. It is owned by the other reflect contract. + // This is necessary because the reflect contract only accepts messages from its owner. + reflect2, _, err := keepers.ContractKeeper.Instantiate(ctx, reflect1.CodeID, reflect1.Contract, reflect1.Contract, []byte("{}"), "reflect2", sdk.NewCoins()) + require.NoError(t, err) + + const SubMsgID = 1 + // Make the reflect1 contract send a submessage to reflect2. That sub-message will error. + execMsg := testdata.ReflectHandleMsg{ + ReflectSubMsg: &testdata.ReflectSubPayload{ + Msgs: []wasmvmtypes.SubMsg{ + { + ID: SubMsgID, + Msg: wasmvmtypes.CosmosMsg{ + Wasm: &wasmvmtypes.WasmMsg{ + Execute: &wasmvmtypes.ExecuteMsg{ + ContractAddr: reflect2.String(), + // This message will error in the reflect contract as an empty "msgs" array is not allowed + Msg: mustMarshal(t, testdata.ReflectHandleMsg{ + Reflect: &testdata.ReflectPayload{ + Msgs: []wasmvmtypes.CosmosMsg{}, + }, + }), + }, + }, + }, + ReplyOn: wasmvmtypes.ReplyError, // we want to see the error + }, + }, + }, + } + execMsgBz := mustMarshal(t, execMsg) + + em := sdk.NewEventManager() + _, err = keepers.ContractKeeper.Execute( + ctx.WithEventManager(em), + reflect1.Contract, + reflect1.CreatorAddr, + execMsgBz, + nil, + ) + require.NoError(t, err) + + // now query the submessage reply + queryMsgBz := mustMarshal(t, testdata.ReflectQueryMsg{ + SubMsgResult: &testdata.SubCall{ + ID: SubMsgID, + }, + }) + queryResponse, err := keepers.WasmKeeper.QuerySmart(ctx, reflect1.Contract, queryMsgBz) + require.NoError(t, err) + var submsgReply wasmvmtypes.Reply + mustUnmarshal(t, queryResponse, &submsgReply) + + assert.Equal(t, "Messages empty. Must reflect at least one message: execute wasm contract failed", submsgReply.Result.Err) +} + func TestInstantiateWithContractDataResponse(t *testing.T) { ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) From 62eaa6eedff4c3a0835cf89de08c060d1d71b799 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Wed, 6 Mar 2024 10:27:26 +0100 Subject: [PATCH 45/45] Add nil checks --- x/wasm/keeper/keeper.go | 20 ++++++++++++++++++++ x/wasm/keeper/relay.go | 20 ++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/x/wasm/keeper/keeper.go b/x/wasm/keeper/keeper.go index 9844f8303a..f6caecdcda 100644 --- a/x/wasm/keeper/keeper.go +++ b/x/wasm/keeper/keeper.go @@ -323,6 +323,10 @@ func (k Keeper) instantiate( if err != nil { return nil, nil, errorsmod.Wrap(types.ErrVMError, err.Error()) } + if res == nil { + // If this gets executed, that's a bug in wasmvm + return nil, nil, errorsmod.Wrap(types.ErrVMError, "internal wasmvm error") + } if res.Err != "" { return nil, nil, types.MarkErrorDeterministic(errorsmod.Wrap(types.ErrInstantiateFailed, res.Err)) } @@ -407,6 +411,10 @@ func (k Keeper) execute(ctx context.Context, contractAddress, caller sdk.AccAddr if execErr != nil { return nil, errorsmod.Wrap(types.ErrVMError, execErr.Error()) } + if res == nil { + // If this gets executed, that's a bug in wasmvm + return nil, errorsmod.Wrap(types.ErrVMError, "internal wasmvm error") + } if res.Err != "" { return nil, types.MarkErrorDeterministic(errorsmod.Wrap(types.ErrExecuteFailed, res.Err)) } @@ -484,6 +492,10 @@ func (k Keeper) migrate( if err != nil { return nil, errorsmod.Wrap(types.ErrVMError, err.Error()) } + if res == nil { + // If this gets executed, that's a bug in wasmvm + return nil, errorsmod.Wrap(types.ErrVMError, "internal wasmvm error") + } if res.Err != "" { return nil, types.MarkErrorDeterministic(errorsmod.Wrap(types.ErrMigrationFailed, res.Err)) } @@ -549,6 +561,10 @@ func (k Keeper) Sudo(ctx context.Context, contractAddress sdk.AccAddress, msg [] if execErr != nil { return nil, errorsmod.Wrap(types.ErrVMError, execErr.Error()) } + if res == nil { + // If this gets executed, that's a bug in wasmvm + return nil, errorsmod.Wrap(types.ErrVMError, "internal wasmvm error") + } if res.Err != "" { return nil, types.MarkErrorDeterministic(errorsmod.Wrap(types.ErrExecuteFailed, res.Err)) } @@ -589,6 +605,10 @@ func (k Keeper) reply(ctx sdk.Context, contractAddress sdk.AccAddress, reply was if execErr != nil { return nil, errorsmod.Wrap(types.ErrVMError, execErr.Error()) } + if res == nil { + // If this gets executed, that's a bug in wasmvm + return nil, errorsmod.Wrap(types.ErrVMError, "internal wasmvm error") + } if res.Err != "" { return nil, types.MarkErrorDeterministic(errorsmod.Wrap(types.ErrExecuteFailed, res.Err)) } diff --git a/x/wasm/keeper/relay.go b/x/wasm/keeper/relay.go index 8be2c287ef..2ccec39eca 100644 --- a/x/wasm/keeper/relay.go +++ b/x/wasm/keeper/relay.go @@ -75,6 +75,10 @@ func (k Keeper) OnConnectChannel( if execErr != nil { return errorsmod.Wrap(types.ErrExecuteFailed, execErr.Error()) } + if res == nil { + // If this gets executed, that's a bug in wasmvm + return errorsmod.Wrap(types.ErrVMError, "internal wasmvm error") + } if res.Err != "" { return types.MarkErrorDeterministic(errorsmod.Wrap(types.ErrExecuteFailed, res.Err)) } @@ -109,6 +113,10 @@ func (k Keeper) OnCloseChannel( if execErr != nil { return errorsmod.Wrap(types.ErrExecuteFailed, execErr.Error()) } + if res == nil { + // If this gets executed, that's a bug in wasmvm + return errorsmod.Wrap(types.ErrVMError, "internal wasmvm error") + } if res.Err != "" { return types.MarkErrorDeterministic(errorsmod.Wrap(types.ErrExecuteFailed, res.Err)) } @@ -145,6 +153,10 @@ func (k Keeper) OnRecvPacket( // all state downstream and not persist any data in ibc-go. // This can be triggered by throwing a panic in the contract } + if res == nil { + // If this gets executed, that's a bug in wasmvm + return nil, errorsmod.Wrap(types.ErrVMError, "internal wasmvm error") + } if res.Err != "" { // return error ACK with non-redacted contract message, state will be reverted return channeltypes.Acknowledgement{ @@ -200,6 +212,10 @@ func (k Keeper) OnAckPacket( if execErr != nil { return errorsmod.Wrap(types.ErrExecuteFailed, execErr.Error()) } + if res == nil { + // If this gets executed, that's a bug in wasmvm + return errorsmod.Wrap(types.ErrVMError, "internal wasmvm error") + } if res.Err != "" { return types.MarkErrorDeterministic(errorsmod.Wrap(types.ErrExecuteFailed, res.Err)) } @@ -231,6 +247,10 @@ func (k Keeper) OnTimeoutPacket( if execErr != nil { return errorsmod.Wrap(types.ErrExecuteFailed, execErr.Error()) } + if res == nil { + // If this gets executed, that's a bug in wasmvm + return errorsmod.Wrap(types.ErrVMError, "internal wasmvm error") + } if res.Err != "" { return types.MarkErrorDeterministic(errorsmod.Wrap(types.ErrExecuteFailed, res.Err)) }